From 0dde66300e1ca13cbef2a6dcf361159696b1ccad Mon Sep 17 00:00:00 2001 From: Sanjay Dalal Date: Wed, 23 Sep 2009 18:03:36 +0000 Subject: [PATCH] CSPACE-81,43,371,394,395 CSPACE-81,394 schema extension supported between consumer and service using multipart messaging, between service and repository using nuxeo repository. metadata-driven using service binding. collectionobject schema extended for testing for natural history domain CSPACE-43 use of JAXB is minimized to consumer side and restricted to just common part on the service side CSPACE-371 nuxeo binding is externalized into tenant binding. CSPACE-395 multi tenancy first cut. example binding for movingimages.us. M services/authentication/client/src/test/java/org/collectionspace/services/authentication/client/AuthenticationServiceTest.java M services/sdk/sample/src/main/java/org/collectionspace/services/sdk/sample/Sample.java D services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java M services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java M services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java M services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java D services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java M services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java M services/collectionobject/service/pom.xml D services/collectionobject/jaxb/src/main/resources/collectionobject.xsd A + services/collectionobject/jaxb/src/main/resources/collectionobjects-common.xsd A services/collectionobject/jaxb/src/main/resources/collectionobjects-naturalhistory.xsd M services/collectionobject/jaxb/pom.xml D services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobject.xsd A + services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-common.xsd A services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-naturalhistory.xsd M services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/OSGI-INF/core-types-contrib.xml A services/collectionobject/3rdparty/pom.xml~ A services/collectionobject/client/received.xml~ A services/collectionobject/client/received.xml A services/collectionobject/client/sent.xml~ M services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java M services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectClient.java M services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectProxy.java A services/collectionobject/client/sent.xml M services/collectionobject/client/pom.xml A services/collectionobject/client/test.xml M services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java M services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml M services/JaxRsServiceProvider/pom.xml A services/common/profiles.xml A services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java A services/common/src/main/java/org/collectionspace/services/common/repository/AbstractDocumentHandler.java M services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java M services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java M services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java M services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java M services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java A + services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceServiceContextListener.java A + services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java A services/common/src/main/java/org/collectionspace/services/common/context A services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java A services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextImpl.java M services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java A services/common/src/main/java/org/collectionspace/services/common/config A services/common/src/main/java/org/collectionspace/services/common/config/ConfigReader.java A services/common/src/main/java/org/collectionspace/services/common/config/AbstractConfigReader.java A services/common/src/main/java/org/collectionspace/services/common/config/ServicesConfigReader.java A services/common/src/main/java/org/collectionspace/services/common/config/TenantBindingConfigReader.java D services/common/src/main/java/org/collectionspace/services/common/ServiceContextListener.java M services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceHandlerFactory.java A services/common/src/main/java/org/collectionspace/services/svn-commit.tmp~ M services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java M services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java M services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java M services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java M services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java M services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java M services/common/src/main/config/service-config.xml A services/common/src/main/config/tenant-bindings.xml A services/common/src/main/svn-commit.tmp~ M services/common/src/main/resources/service-config.xsd A services/common/src/main/resources/types.xsd A services/common/src/main/resources/tenant.xsd A services/common/src/main/resources/service.xsd M services/common/pom.xml M services/common/build.xml _M services/acquisition/service M services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionResource.java D services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionService.java M services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionDocumentModelHandler.java M services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionHandlerFactory.java _M services/acquisition/jaxb D services/acquisition/jaxb/src/main/resources/acquisition.xsd A + services/acquisition/jaxb/src/main/resources/acquisitions-common.xsd _M services/acquisition/3rdparty/nuxeo-platform-cs-acquisition D services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/schemas/acquisition.xsd A + services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/schemas/acquisitions-common.xsd M services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/OSGI-INF/core-types-contrib.xml _M services/acquisition/client M services/acquisition/client/src/test/java/org/collectionspace/services/client/test/AcquisitionServiceTest.java M services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionClient.java M services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionProxy.java M services/pom.xml M services/id/service/pom.xml M services/id/jaxb/pom.xml _M services/query/service _M services/IntegrationTests A services/intake/service/profiles.xml M services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeResource.java D services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeService.java D services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeServiceNuxeoImpl.java M services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeHandlerFactory.java M services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeRepresenationHandler.java M services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeDocumentModelHandler.java A + services/intake/jaxb/src/main/resources/intakes-common.xsd D services/intake/jaxb/src/main/resources/intake.xsd M services/intake/jaxb/pom.xml A + services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/schemas/intakes-common.xsd D services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/schemas/intake.xsd M services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/OSGI-INF/core-types-contrib.xml M services/intake/client/src/test/java/org/collectionspace/services/client/test/IntakeServiceTest.java M services/intake/client/src/main/java/org/collectionspace/services/client/IntakeClient.java M services/intake/client/src/main/java/org/collectionspace/services/client/IntakeProxy.java M services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java M services/client/src/main/java/org/collectionspace/services/client/test/ServiceTest.java M services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java --- services/JaxRsServiceProvider/pom.xml | 8 +- .../CollectionSpaceJaxRsApplication.java | 10 +- .../src/main/webapp/WEB-INF/web.xml | 2 +- .../resources/OSGI-INF/core-types-contrib.xml | 4 +- ...cquisition.xsd => acquisitions-common.xsd} | 0 .../services/client/AcquisitionClient.java | 18 +- .../services/client/AcquisitionProxy.java | 20 +- .../client/test/AcquisitionServiceTest.java | 431 ++++++------- ...cquisition.xsd => acquisitions-common.xsd} | 10 +- .../acquisition/AcquisitionResource.java | 144 ++--- .../acquisition/AcquisitionService.java | 38 -- .../AcquisitionDocumentModelHandler.java | 88 ++- .../nuxeo/AcquisitionHandlerFactory.java | 4 +- .../client/AuthenticationServiceTest.java | 199 +++--- .../client/test/AbstractServiceTest.java | 196 +++--- .../services/client/test/ServiceTest.java | 51 +- .../resources/OSGI-INF/core-types-contrib.xml | 22 +- ...bject.xsd => collectionobjects-common.xsd} | 0 .../collectionobjects-naturalhistory.xsd | 15 + services/collectionobject/3rdparty/pom.xml~ | 36 ++ services/collectionobject/client/pom.xml | 6 +- services/collectionobject/client/received.xml | 5 + .../collectionobject/client/received.xml~ | 6 + services/collectionobject/client/sent.xml | 6 + services/collectionobject/client/sent.xml~ | 3 + .../client/CollectionObjectClient.java | 24 +- .../client/CollectionObjectProxy.java | 21 +- .../test/CollectionObjectServiceTest.java | 223 ++++--- services/collectionobject/client/test.xml | 8 + services/collectionobject/jaxb/pom.xml | 2 +- ...bject.xsd => collectionobjects-common.xsd} | 33 +- .../collectionobjects-naturalhistory.xsd | 37 ++ services/collectionobject/service/pom.xml | 6 +- .../CollectionObjectResource.java | 169 +++-- .../CollectionObjectService.java | 38 -- .../CollectionObjectDocumentModelHandler.java | 151 ++--- .../nuxeo/CollectionObjectHandlerFactory.java | 6 +- .../CollectionObjectRepresenationHandler.java | 51 +- .../CollectionObjectServiceNuxeoImpl.java | 224 ------- services/common/build.xml | 9 +- services/common/pom.xml | 55 +- services/common/profiles.xml | 4 + .../common/src/main/config/service-config.xml | 27 +- .../src/main/config/tenant-bindings.xml | 112 ++++ .../AbstractCollectionSpaceResource.java | 70 +++ .../common/CollectionSpaceHandlerFactory.java | 31 +- .../common/CollectionSpaceResource.java | 111 ++-- ...ollectionSpaceServiceContextListener.java} | 14 +- .../services/common/ServiceMain.java | 132 ++-- .../common/config/AbstractConfigReader.java | 86 +++ .../services/common/config/ConfigReader.java | 54 ++ .../common/config/ServicesConfigReader.java | 94 +++ .../config/TenantBindingConfigReader.java | 193 ++++++ .../common/context/ServiceContext.java | 161 +++++ .../common/context/ServiceContextImpl.java | 239 ++++++++ .../repository/AbstractDocumentHandler.java | 188 ++++++ .../common/repository/DocumentException.java | 2 +- .../common/repository/DocumentHandler.java | 175 ++++-- .../common/repository/DocumentUtils.java | 172 ++++++ .../common/repository/RepositoryClient.java | 24 +- .../repository/RepositoryClientFactory.java | 35 +- .../client/java/DocumentModelHandler.java | 208 ++++--- .../nuxeo/client/java/NuxeoConnector.java | 48 +- .../client/java/RepositoryJavaClient.java | 579 +++++++++--------- .../client/rest/RepositoryRESTClient.java | 47 +- .../client/rest/RepresentationHandler.java | 99 +-- .../services/nuxeo/util/NuxeoUtils.java | 142 ++--- .../collectionspace/services/svn-commit.tmp~ | 4 + .../src/main/resources/service-config.xsd | 76 +-- .../common/src/main/resources/service.xsd | 170 +++++ services/common/src/main/resources/tenant.xsd | 58 ++ services/common/src/main/resources/types.xsd | 43 ++ services/common/src/main/svn-commit.tmp~ | 5 + services/id/jaxb/pom.xml | 1 - services/id/service/pom.xml | 2 +- .../resources/OSGI-INF/core-types-contrib.xml | 4 +- .../{intake.xsd => intakes-common.xsd} | 0 .../services/client/IntakeClient.java | 19 +- .../services/client/IntakeProxy.java | 20 +- .../client/test/IntakeServiceTest.java | 448 +++++++------- services/intake/jaxb/pom.xml | 4 +- .../{intake.xsd => intakes-common.xsd} | 10 +- services/intake/service/profiles.xml | 4 + .../services/intake/IntakeResource.java | 148 ++--- .../services/intake/IntakeService.java | 38 -- .../intake/IntakeServiceNuxeoImpl.java | 215 ------- .../nuxeo/IntakeDocumentModelHandler.java | 154 +---- .../intake/nuxeo/IntakeHandlerFactory.java | 6 +- .../nuxeo/IntakeRepresenationHandler.java | 47 +- services/pom.xml | 14 +- .../relation/NewRelationResource.java | 54 +- .../services/sdk/sample/Sample.java | 16 +- 92 files changed, 4099 insertions(+), 2887 deletions(-) rename services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/schemas/{acquisition.xsd => acquisitions-common.xsd} (100%) rename services/acquisition/jaxb/src/main/resources/{acquisition.xsd => acquisitions-common.xsd} (85%) delete mode 100644 services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionService.java rename services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/{collectionobject.xsd => collectionobjects-common.xsd} (100%) create mode 100644 services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-naturalhistory.xsd create mode 100644 services/collectionobject/3rdparty/pom.xml~ create mode 100644 services/collectionobject/client/received.xml create mode 100644 services/collectionobject/client/received.xml~ create mode 100644 services/collectionobject/client/sent.xml create mode 100644 services/collectionobject/client/sent.xml~ create mode 100644 services/collectionobject/client/test.xml rename services/collectionobject/jaxb/src/main/resources/{collectionobject.xsd => collectionobjects-common.xsd} (57%) create mode 100644 services/collectionobject/jaxb/src/main/resources/collectionobjects-naturalhistory.xsd delete mode 100644 services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java delete mode 100644 services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java create mode 100644 services/common/profiles.xml create mode 100644 services/common/src/main/config/tenant-bindings.xml create mode 100644 services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java rename services/common/src/main/java/org/collectionspace/services/common/{ServiceContextListener.java => CollectionSpaceServiceContextListener.java} (58%) create mode 100644 services/common/src/main/java/org/collectionspace/services/common/config/AbstractConfigReader.java create mode 100644 services/common/src/main/java/org/collectionspace/services/common/config/ConfigReader.java create mode 100644 services/common/src/main/java/org/collectionspace/services/common/config/ServicesConfigReader.java create mode 100644 services/common/src/main/java/org/collectionspace/services/common/config/TenantBindingConfigReader.java create mode 100644 services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java create mode 100644 services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextImpl.java create mode 100644 services/common/src/main/java/org/collectionspace/services/common/repository/AbstractDocumentHandler.java create mode 100644 services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java create mode 100644 services/common/src/main/java/org/collectionspace/services/svn-commit.tmp~ create mode 100644 services/common/src/main/resources/service.xsd create mode 100644 services/common/src/main/resources/tenant.xsd create mode 100644 services/common/src/main/resources/types.xsd create mode 100644 services/common/src/main/svn-commit.tmp~ rename services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/schemas/{intake.xsd => intakes-common.xsd} (100%) rename services/intake/jaxb/src/main/resources/{intake.xsd => intakes-common.xsd} (95%) create mode 100644 services/intake/service/profiles.xml delete mode 100644 services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeService.java delete mode 100644 services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeServiceNuxeoImpl.java diff --git a/services/JaxRsServiceProvider/pom.xml b/services/JaxRsServiceProvider/pom.xml index c86a2584d..a5137dd18 100644 --- a/services/JaxRsServiceProvider/pom.xml +++ b/services/JaxRsServiceProvider/pom.xml @@ -42,7 +42,7 @@ org.collectionspace.services.acquisition.service 1.0 - + commons-io commons-io @@ -70,12 +70,12 @@ org.jboss.resteasy resteasy-jaxb-provider - 1.0.2.GA + 1.1.GA org.jboss.resteasy resteasy-multipart-provider - 1.0.2.GA + 1.1.GA junit diff --git a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java index 7f77d8e3f..ad5448643 100644 --- a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java +++ b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java @@ -3,10 +3,10 @@ package org.collectionspace.services.jaxrs; import org.collectionspace.services.collectionobject.CollectionObjectResource; import org.collectionspace.services.id.IDResource; import org.collectionspace.services.intake.IntakeResource; -//import org.collectionspace.services.relation.RelationResource; -import org.collectionspace.services.relation.NewRelationResource; +////import org.collectionspace.services.relation.RelationResource; +//import org.collectionspace.services.relation.NewRelationResource; import org.collectionspace.services.acquisition.AcquisitionResource; -import org.collectionspace.services.query.QueryResource; +//import org.collectionspace.services.query.QueryResource; import javax.ws.rs.core.Application; import java.util.HashSet; @@ -24,8 +24,8 @@ public class CollectionSpaceJaxRsApplication extends Application { singletons.add(new IntakeResource()); singletons.add(new AcquisitionResource()); // singletons.add(new RelationResource()); - singletons.add(new NewRelationResource()); - singletons.add(new QueryResource()); + //singletons.add(new NewRelationResource()); +// singletons.add(new QueryResource()); // singletons.add(new DomainIdentifierResource()); // singletons.add(new PingResource()); } diff --git a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml index 812508a23..6d52948b7 100644 --- a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml +++ b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml @@ -30,7 +30,7 @@ - org.collectionspace.services.common.ServiceContextListener + org.collectionspace.services.common.CollectionSpaceServiceContextListener diff --git a/services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/OSGI-INF/core-types-contrib.xml b/services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/OSGI-INF/core-types-contrib.xml index 3554f7d58..4a8a87cc7 100644 --- a/services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/OSGI-INF/core-types-contrib.xml +++ b/services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/OSGI-INF/core-types-contrib.xml @@ -1,13 +1,13 @@ - + - + diff --git a/services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/schemas/acquisition.xsd b/services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/schemas/acquisitions-common.xsd similarity index 100% rename from services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/schemas/acquisition.xsd rename to services/acquisition/3rdparty/nuxeo-platform-cs-acquisition/src/main/resources/schemas/acquisitions-common.xsd diff --git a/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionClient.java b/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionClient.java index e4092c686..06390f972 100644 --- a/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionClient.java +++ b/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionClient.java @@ -2,12 +2,12 @@ package org.collectionspace.services.client; import javax.ws.rs.core.Response; -import org.collectionspace.services.acquisition.Acquisition; -import org.collectionspace.services.acquisition.AcquisitionList; - +import org.collectionspace.services.acquisition.AcquisitionsCommonList; import org.jboss.resteasy.client.ProxyFactory; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.spi.ResteasyProviderFactory; /** @@ -51,7 +51,7 @@ public class AcquisitionClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#getIntake() */ - public ClientResponse readList() { + public ClientResponse readList() { return acquisitionProxy.readList(); } @@ -60,7 +60,7 @@ public class AcquisitionClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#getIntake(java.lang.String) */ - public ClientResponse read(String csid) { + public ClientResponse read(String csid) { return acquisitionProxy.read(csid); } @@ -69,8 +69,8 @@ public class AcquisitionClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#createIntake(org.collectionspace.hello.Intake) */ - public ClientResponse create(Acquisition intake) { - return acquisitionProxy.create(intake); + public ClientResponse create(MultipartOutput multipart) { + return acquisitionProxy.create(multipart); } /** @@ -79,8 +79,8 @@ public class AcquisitionClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#updateIntake(java.lang.Long, org.collectionspace.hello.Intake) */ - public ClientResponse update(String csid, Acquisition intake) { - return acquisitionProxy.update(csid, intake); + public ClientResponse update(String csid, MultipartOutput multipart) { + return acquisitionProxy.update(csid, multipart); } /** diff --git a/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionProxy.java b/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionProxy.java index b74f11241..0a7c02e45 100644 --- a/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionProxy.java +++ b/services/acquisition/client/src/main/java/org/collectionspace/services/client/AcquisitionProxy.java @@ -10,37 +10,39 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Response; -import org.collectionspace.services.acquisition.Acquisition; -import org.collectionspace.services.acquisition.AcquisitionList; +import org.collectionspace.services.acquisition.AcquisitionsCommonList; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; /** * @version $Revision:$ */ @Path("/acquisitions/") -@Produces({"application/xml"}) -@Consumes({"application/xml"}) +@Produces({"multipart/mixed"}) +@Consumes({"multipart/mixed"}) public interface AcquisitionProxy { @GET - ClientResponse readList(); + @Produces({"application/xml"}) + ClientResponse readList(); //(C)reate @POST - ClientResponse create(Acquisition co); + ClientResponse create(MultipartOutput multipart); //(R)ead @GET @Path("/{csid}") - ClientResponse read(@PathParam("csid") String csid); + ClientResponse read(@PathParam("csid") String csid); //(U)pdate @PUT @Path("/{csid}") - ClientResponse update(@PathParam("csid") String csid, Acquisition co); + ClientResponse update(@PathParam("csid") String csid, MultipartOutput multipart); //(D)elete @DELETE @Path("/{csid}") ClientResponse delete(@PathParam("csid") String csid); -} \ No newline at end of file +} diff --git a/services/acquisition/client/src/test/java/org/collectionspace/services/client/test/AcquisitionServiceTest.java b/services/acquisition/client/src/test/java/org/collectionspace/services/client/test/AcquisitionServiceTest.java index 6db1f4eb5..c34959d93 100644 --- a/services/acquisition/client/src/test/java/org/collectionspace/services/client/test/AcquisitionServiceTest.java +++ b/services/acquisition/client/src/test/java/org/collectionspace/services/client/test/AcquisitionServiceTest.java @@ -20,20 +20,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.collectionspace.services.client.test; +package org.collectionspace.services.client.test; import java.util.List; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; import org.collectionspace.services.client.AcquisitionClient; -import org.collectionspace.services.client.test.ServiceRequestType; -import org.collectionspace.services.acquisition.Acquisition; -import org.collectionspace.services.acquisition.AcquisitionList; +import org.collectionspace.services.acquisition.AcquisitionsCommon; +import org.collectionspace.services.acquisition.AcquisitionsCommonList; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; +import org.jboss.resteasy.plugins.providers.multipart.OutputPart; import org.testng.Assert; import org.testng.annotations.Test; @@ -51,13 +52,10 @@ public class AcquisitionServiceTest extends AbstractServiceTest { final String SERVICE_PATH_COMPONENT = "acquisitions"; private String knownResourceId = null; - // --------------------------------------------------------------- // CRUD tests : CREATE tests // --------------------------------------------------------------- - // Success outcomes - @Override @Test public void create() { @@ -69,8 +67,10 @@ public class AcquisitionServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. String identifier = createIdentifier(); - Acquisition acquisition = createAcquisitionInstance(identifier); - ClientResponse res = client.create(acquisition); + + MultipartOutput multipart = createAcquisitionInstance(identifier); + ClientResponse res = client.create(multipart); + int statusCode = res.getStatus(); // Check the status code of the response: does it match @@ -81,12 +81,13 @@ public class AcquisitionServiceTest extends AbstractServiceTest { // Does it exactly match the expected status code? verbose("create: status = " + statusCode); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); // Store the ID returned from this create operation for // additional tests below. knownResourceId = extractId(res); + verbose("create: knownResourceId=" + knownResourceId); } @Override @@ -98,294 +99,309 @@ public class AcquisitionServiceTest extends AbstractServiceTest { } // Failure outcomes - // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. - public void createWithEmptyEntityBody() {} - public void createWithMalformedXml() {} - public void createWithWrongXmlSchema() {} + public void createWithEmptyEntityBody() { + } -/* + public void createWithMalformedXml() { + } + + public void createWithWrongXmlSchema() { + } + + /* @Override @Test(dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithMalformedXml() { - // Perform setup. - setupCreateWithMalformedXml(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - final String entity = MALFORMED_XML_DATA; // Constant from base class. - int statusCode = submitRequest(method, url, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("createWithMalformedXml url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithMalformedXml(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + final String entity = MALFORMED_XML_DATA; // Constant from base class. + int statusCode = submitRequest(method, url, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("createWithMalformedXml url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithWrongXmlSchema() { - // Perform setup. - setupCreateWithWrongXmlSchema(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - final String entity = WRONG_XML_SCHEMA_DATA; - int statusCode = submitRequest(method, url, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("createWithWrongSchema url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithWrongXmlSchema(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + final String entity = WRONG_XML_SCHEMA_DATA; + int statusCode = submitRequest(method, url, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("createWithWrongSchema url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } -*/ - + */ // --------------------------------------------------------------- // CRUD tests : READ tests // --------------------------------------------------------------- - // Success outcomes - @Override @Test(dependsOnMethods = {"create"}) public void read() { - + // Perform setup. setupRead(); // Submit the request to the service and store the response. - ClientResponse res = client.read(knownResourceId); + ClientResponse res = client.read(knownResourceId); int statusCode = res.getStatus(); - + // Check the status code of the response: does it match // the expected response(s)? verbose("read: status = " + statusCode); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + //FIXME: remove the following try catch once Aron fixes signatures + try{ + MultipartInput input = (MultipartInput) res.getEntity(); + AcquisitionsCommon acquistionObject = (AcquisitionsCommon) extractPart(input, + getCommonPartName(), AcquisitionsCommon.class); + Assert.assertNotNull(acquistionObject); + }catch(Exception e){ + throw new RuntimeException(e); + } } // Failure outcomes - @Override @Test(dependsOnMethods = {"read"}) public void readNonExistent() { // Perform setup. setupReadNonExistent(); - + // Submit the request to the service and store the response. - ClientResponse res = client.read(NON_EXISTENT_ID); + ClientResponse res = client.read(NON_EXISTENT_ID); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("readNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - // --------------------------------------------------------------- // CRUD tests : READ_LIST tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = {"createList"}) + @Test(dependsOnMethods = {"createList", "read"}) public void readList() { - + // Perform setup. setupReadList(); // Submit the request to the service and store the response. - ClientResponse res = client.readList(); - AcquisitionList list = res.getEntity(); + ClientResponse res = client.readList(); + AcquisitionsCommonList list = res.getEntity(); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("readList: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); // Optionally output additional data about list members for debugging. boolean iterateThroughList = false; - if (iterateThroughList && logger.isDebugEnabled()) { - List items = - list.getAcquisitionListItem(); + if(iterateThroughList && logger.isDebugEnabled()){ + List items = + list.getAcquisitionListItem(); int i = 0; - for(AcquisitionList.AcquisitionListItem item : items){ + for(AcquisitionsCommonList.AcquisitionListItem item : items){ verbose("readList: list-item[" + i + "] csid=" + - item.getCsid()); + item.getCsid()); verbose("readList: list-item[" + i + "] objectNumber=" + - item.getAccessiondate()); + item.getAccessiondate()); verbose("readList: list-item[" + i + "] URI=" + - item.getUri()); + item.getUri()); i++; } } - + } // Failure outcomes - // None at present. - - // --------------------------------------------------------------- // CRUD tests : UPDATE tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = {"create"}) + @Test(dependsOnMethods = {"read"}) public void update() { - + // Perform setup. setupUpdate(); - - // Retrieve an existing resource that we can update. - ClientResponse res = client.read(knownResourceId); - verbose("read: status = " + res.getStatus()); - Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); - Acquisition acquisition = res.getEntity(); - verbose("Got object to update with ID: " + knownResourceId, - acquisition, Acquisition.class); - - // Update the content of this resource. - acquisition.setAccessiondate("updated-" + acquisition.getAccessiondate()); -// acquisition.setEntryDate("updated-" + acquisition.getEntryDate()); - - // Submit the request to the service and store the response. - res = client.update(knownResourceId, acquisition); - int statusCode = res.getStatus(); - Acquisition updatedObject = res.getEntity(); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("update: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - - // Check the contents of the response: does it match - // what was submitted? - verbose("update: ", updatedObject, Acquisition.class); - Assert.assertEquals(updatedObject.getAccessiondate(), - acquisition.getAccessiondate(), - "Data in updated object did not match submitted data."); + try{ //ideally, just remove try-catch and let the exception bubble up + // Retrieve an existing resource that we can update. + ClientResponse res = + client.read(knownResourceId); + verbose("update: read status = " + res.getStatus()); + Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); + + verbose("got object to update with ID: " + knownResourceId); + MultipartInput input = (MultipartInput) res.getEntity(); + AcquisitionsCommon acquisition = (AcquisitionsCommon) extractPart(input, + getCommonPartName(), AcquisitionsCommon.class); + Assert.assertNotNull(acquisition); + + // Update the content of this resource. + acquisition.setAccessiondate("updated-" + acquisition.getAccessiondate()); + verbose("updated object", acquisition, AcquisitionsCommon.class); + // Submit the request to the service and store the response. + MultipartOutput output = new MultipartOutput(); + OutputPart commonPart = output.addPart(acquisition, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", getCommonPartName()); + + res = client.update(knownResourceId, output); + int statusCode = res.getStatus(); + // Check the status code of the response: does it match the expected response(s)? + verbose("update: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + + input = (MultipartInput) res.getEntity(); + AcquisitionsCommon updatedAcquisition = + (AcquisitionsCommon) extractPart(input, + getCommonPartName(), AcquisitionsCommon.class); + Assert.assertNotNull(updatedAcquisition); + + Assert.assertEquals(updatedAcquisition.getAccessiondate(), + acquisition.getAccessiondate(), + "Data in updated object did not match submitted data."); + }catch(Exception e){ + e.printStackTrace(); + } } // Failure outcomes - // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. - public void updateWithEmptyEntityBody() {} - public void updateWithMalformedXml() {} - public void updateWithWrongXmlSchema() {} + public void updateWithEmptyEntityBody() { + } -/* + public void updateWithMalformedXml() { + } + + public void updateWithWrongXmlSchema() { + } + + /* @Override @Test(dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithEmptyEntityBody() { - // Perform setup. - setupUpdateWithEmptyEntityBody(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - String mediaType = MediaType.APPLICATION_XML; - final String entity = ""; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("updateWithEmptyEntityBody url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithEmptyEntityBody(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + String mediaType = MediaType.APPLICATION_XML; + final String entity = ""; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("updateWithEmptyEntityBody url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithEmptyEntityBody() { - // Perform setup. - setupCreateWithEmptyEntityBody(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - String mediaType = MediaType.APPLICATION_XML; - final String entity = ""; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("createWithEmptyEntityBody url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithEmptyEntityBody(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + String mediaType = MediaType.APPLICATION_XML; + final String entity = ""; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("createWithEmptyEntityBody url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithMalformedXml() { - // Perform setup. - setupUpdateWithMalformedXml(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - final String entity = MALFORMED_XML_DATA; - int statusCode = submitRequest(method, url, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("updateWithMalformedXml: url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithMalformedXml(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + final String entity = MALFORMED_XML_DATA; + int statusCode = submitRequest(method, url, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("updateWithMalformedXml: url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithWrongXmlSchema() { - // Perform setup. - setupUpdateWithWrongXmlSchema(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - final String entity = WRONG_XML_SCHEMA_DATA; - int statusCode = submitRequest(method, url, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("updateWithWrongSchema: url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithWrongXmlSchema(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + final String entity = WRONG_XML_SCHEMA_DATA; + int statusCode = submitRequest(method, url, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("updateWithWrongSchema: url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } -*/ - + */ @Override @Test(dependsOnMethods = {"update", "testSubmitRequest"}) public void updateNonExistent() { @@ -396,28 +412,25 @@ public class AcquisitionServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. // Note: The ID used in this 'create' call may be arbitrary. // The only relevant ID may be the one used in update(), below. - Acquisition acquisition = createAcquisitionInstance(NON_EXISTENT_ID); - ClientResponse res = - client.update(NON_EXISTENT_ID, acquisition); + MultipartOutput multipart = createAcquisitionInstance(NON_EXISTENT_ID); + ClientResponse res = + client.update(NON_EXISTENT_ID, multipart); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("updateNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } // --------------------------------------------------------------- // CRUD tests : DELETE tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = - {"create", "read", "update"}) + @Test(dependsOnMethods = {"create", "read", "update"}) public void delete() { // Perform setup. @@ -431,12 +444,11 @@ public class AcquisitionServiceTest extends AbstractServiceTest { // the expected response(s)? verbose("delete: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } // Failure outcomes - @Override @Test(dependsOnMethods = {"delete"}) public void deleteNonExistent() { @@ -452,15 +464,13 @@ public class AcquisitionServiceTest extends AbstractServiceTest { // the expected response(s)? verbose("deleteNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - // --------------------------------------------------------------- // Utility tests : tests of code used in tests above // --------------------------------------------------------------- - /** * Tests the code for manually submitting data that is used by several * of the methods above. @@ -475,36 +485,31 @@ public class AcquisitionServiceTest extends AbstractServiceTest { String method = ServiceRequestType.READ.httpMethodName(); String url = getResourceURL(knownResourceId); int statusCode = submitRequest(method, url); - + // Check the status code of the response: does it match // the expected response(s)? verbose("testSubmitRequest: url=" + url + " status=" + statusCode); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } + } // --------------------------------------------------------------- // Utility methods used by tests above // --------------------------------------------------------------- - @Override public String getServicePathComponent() { return SERVICE_PATH_COMPONENT; } - - private Acquisition createAcquisitionInstance(String identifier) { - Acquisition acquisition = - createAcquisitionInstance( - "entryNumber-" + identifier, - "entryDate-" + identifier); - return acquisition; - } - - private Acquisition createAcquisitionInstance(String entryNumber, String entryDate) { - Acquisition acquisition = new Acquisition(); -// acquisition.setEntryNumber(entryNumber); - acquisition.setAccessiondate(entryDate); - return acquisition; - } + + private MultipartOutput createAcquisitionInstance(String identifier) { + AcquisitionsCommon acquisition = new AcquisitionsCommon(); + acquisition.setAccessiondate("accessionDate-" + identifier); + MultipartOutput multipart = new MultipartOutput(); + OutputPart commonPart = multipart.addPart(acquisition, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", getCommonPartName()); + + verbose("to be created, collectionobject common ", acquisition, AcquisitionsCommon.class); + return multipart; + } } diff --git a/services/acquisition/jaxb/src/main/resources/acquisition.xsd b/services/acquisition/jaxb/src/main/resources/acquisitions-common.xsd similarity index 85% rename from services/acquisition/jaxb/src/main/resources/acquisition.xsd rename to services/acquisition/jaxb/src/main/resources/acquisitions-common.xsd index 59466e746..46f45f474 100644 --- a/services/acquisition/jaxb/src/main/resources/acquisition.xsd +++ b/services/acquisition/jaxb/src/main/resources/acquisitions-common.xsd @@ -1,9 +1,9 @@ @@ -12,7 +12,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionResource.java b/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionResource.java index ff4a5c44d..41ca543bd 100644 --- a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionResource.java +++ b/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionResource.java @@ -36,53 +36,57 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; -import org.collectionspace.services.acquisition.AcquisitionList.*; - -import org.collectionspace.services.acquisition.nuxeo.AcquisitionConstants; import org.collectionspace.services.acquisition.nuxeo.AcquisitionHandlerFactory; -import org.collectionspace.services.common.NuxeoClientType; -import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.AbstractCollectionSpaceResource; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.common.repository.DocumentHandler; -import org.collectionspace.services.common.repository.RepositoryClient; -import org.collectionspace.services.common.repository.RepositoryClientFactory; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.util.HttpResponseCodes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path("/acquisitions") -@Consumes("application/xml") -@Produces("application/xml") -public class AcquisitionResource { +@Consumes("multipart/mixed") +@Produces("multipart/mixed") +public class AcquisitionResource + extends AbstractCollectionSpaceResource { - public final static String ACQUISITION_SERVICE_NAME = "acquisitions"; + final private String serviceName = "acquisitions"; final Logger logger = LoggerFactory.getLogger(AcquisitionResource.class); - //FIXME retrieve client type from configuration - final static NuxeoClientType CLIENT_TYPE = ServiceMain.getInstance().getNuxeoClientType(); + + @Override + public String getServiceName() { + return serviceName; + } + + @Override + public DocumentHandler createDocumentHandler(ServiceContext ctx) throws Exception { + DocumentHandler docHandler = AcquisitionHandlerFactory.getInstance().getHandler( + ctx.getRepositoryClientType().toString()); + docHandler.setServiceContext(ctx); + if(ctx.getInput() != null){ + Object obj = ctx.getInputPart(ctx.getCommonPartLabel(), AcquisitionsCommon.class); + if(obj != null){ + docHandler.setCommonPart((AcquisitionsCommon) obj); + } + } + return docHandler; + } public AcquisitionResource() { // do nothing } @POST - public Response createAcquisition( - Acquisition acquisitionObject) { + public Response createAcquisition(MultipartInput input) { - String csid = null; try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - AcquisitionHandlerFactory handlerFactory = AcquisitionHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - handler.setCommonObject(acquisitionObject); - csid = client.create(ACQUISITION_SERVICE_NAME, handler); - acquisitionObject.setCsid(csid); - if(logger.isDebugEnabled()){ - verbose("createAcquisition: ", acquisitionObject); - } + ServiceContext ctx = createServiceContext(input); + DocumentHandler handler = createDocumentHandler(ctx); + String csid = getRepositoryClient(ctx).create(ctx, handler); UriBuilder path = UriBuilder.fromResource(AcquisitionResource.class); path.path("" + csid); Response response = Response.created(path.build()).build(); @@ -99,10 +103,10 @@ public class AcquisitionResource { @GET @Path("{csid}") - public Acquisition getAcquisition( + public MultipartOutput getAcquisition( @PathParam("csid") String csid) { if(logger.isDebugEnabled()){ - verbose("getAcquisition with csid=" + csid); + logger.debug("getAcquisition with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("getAcquisition: missing csid!"); @@ -111,14 +115,12 @@ public class AcquisitionResource { "text/plain").build(); throw new WebApplicationException(response); } - Acquisition acquisitionObject = null; + MultipartOutput result = null; try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - AcquisitionHandlerFactory handlerFactory = AcquisitionHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - client.get(csid, handler); - acquisitionObject = (Acquisition) handler.getCommonObject(); + ServiceContext ctx = createServiceContext(null); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).get(ctx, csid, handler); + result = ctx.getOutput(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ logger.debug("getAcquisition", dnfe); @@ -136,28 +138,24 @@ public class AcquisitionResource { throw new WebApplicationException(response); } - if(acquisitionObject == null){ + if(result == null){ Response response = Response.status(Response.Status.NOT_FOUND).entity( "Get failed, the requested Acquisition CSID:" + csid + ": was not found.").type( "text/plain").build(); throw new WebApplicationException(response); } - if(logger.isDebugEnabled()){ - verbose("getAcquisition: ", acquisitionObject); - } - return acquisitionObject; + return result; } @GET - public AcquisitionList getAcquisitionList(@Context UriInfo ui) { - AcquisitionList acquisitionObjectList = new AcquisitionList(); + @Produces("application/xml") + public AcquisitionsCommonList getAcquisitionList(@Context UriInfo ui) { + AcquisitionsCommonList acquisitionObjectList = new AcquisitionsCommonList(); try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - AcquisitionHandlerFactory handlerFactory = AcquisitionHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - client.getAll(ACQUISITION_SERVICE_NAME, handler); - acquisitionObjectList = (AcquisitionList) handler.getCommonObjectList(); + ServiceContext ctx = createServiceContext(null); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).getAll(ctx, handler); + acquisitionObjectList = (AcquisitionsCommonList) handler.getCommonPartList(); }catch(Exception e){ if(logger.isDebugEnabled()){ logger.debug("Caught exception in getAcquisitionList", e); @@ -171,11 +169,11 @@ public class AcquisitionResource { @PUT @Path("{csid}") - public Acquisition updateAcquisition( + public MultipartOutput updateAcquisition( @PathParam("csid") String csid, - Acquisition theUpdate) { + MultipartInput theUpdate) { if(logger.isDebugEnabled()){ - verbose("updateAcquisition with csid=" + csid); + logger.debug("updateAcquisition with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("updateAcquisition: missing csid!"); @@ -185,15 +183,14 @@ public class AcquisitionResource { throw new WebApplicationException(response); } if(logger.isDebugEnabled()){ - verbose("updateAcquisition with input: ", theUpdate); + logger.debug("updateAcquisition with input: ", theUpdate); } + MultipartOutput result = null; try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - AcquisitionHandlerFactory handlerFactory = AcquisitionHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - handler.setCommonObject(theUpdate); - client.update(csid, handler); + ServiceContext ctx = createServiceContext(theUpdate); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).update(ctx, csid, handler); + result = ctx.getOutput(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ logger.debug("caugth exception in updateAcquisition", dnfe); @@ -207,7 +204,7 @@ public class AcquisitionResource { Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build(); throw new WebApplicationException(response); } - return theUpdate; + return result; } @DELETE @@ -215,7 +212,7 @@ public class AcquisitionResource { public Response deleteAcquisition(@PathParam("csid") String csid) { if(logger.isDebugEnabled()){ - verbose("deleteAcquisition with csid=" + csid); + logger.debug("deleteAcquisition with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("deleteAcquisition: missing csid!"); @@ -225,9 +222,8 @@ public class AcquisitionResource { throw new WebApplicationException(response); } try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - client.delete(csid); + ServiceContext ctx = createServiceContext(null); + getRepositoryClient(ctx).delete(ctx, csid); return Response.status(HttpResponseCodes.SC_OK).build(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ @@ -245,22 +241,4 @@ public class AcquisitionResource { } - private void verbose(String msg, Acquisition acquisitionObject) { - try{ - verbose(msg); - JAXBContext jc = JAXBContext.newInstance( - Acquisition.class); - - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - m.marshal(acquisitionObject, System.out); - }catch(Exception e){ - e.printStackTrace(); - } - - } - - private void verbose(String msg) { - System.out.println("AcquisitionResource. " + msg); - } } diff --git a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionService.java b/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionService.java deleted file mode 100644 index 68009d3fc..000000000 --- a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/AcquisitionService.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * - */ -package org.collectionspace.services.acquisition; - -import java.io.IOException; -import org.dom4j.Document; -import org.dom4j.DocumentException; - -import org.collectionspace.services.acquisition.Acquisition; - -/** - * @author remillet - * - */ -public interface AcquisitionService { - - public final static String ACQUISITION_SCHEMA_NAME = "acquisition"; - - // Create - Document postAcquisition(Acquisition co) - throws DocumentException, IOException; - - // Read single object - Document getAcquisition(String csid) throws DocumentException, - IOException; - - // Read a list of objects - Document getAcquisitionList() throws DocumentException, IOException; - - // Update - Document putAcquisition(String csid, Acquisition theUpdate) - throws DocumentException, IOException; - - // Delete - Document deleteAcquisition(String csid) throws DocumentException, - IOException; -} diff --git a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionDocumentModelHandler.java b/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionDocumentModelHandler.java index 1570184da..33d3cc4d9 100644 --- a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionDocumentModelHandler.java +++ b/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionDocumentModelHandler.java @@ -28,11 +28,10 @@ import java.util.List; import org.collectionspace.services.AcquisitionJAXBSchema; import org.collectionspace.services.common.repository.DocumentWrapper; -import org.collectionspace.services.acquisition.Acquisition; -import org.collectionspace.services.acquisition.AcquisitionList; -import org.collectionspace.services.acquisition.AcquisitionList.AcquisitionListItem; +import org.collectionspace.services.acquisition.AcquisitionsCommon; +import org.collectionspace.services.acquisition.AcquisitionsCommonList; +import org.collectionspace.services.acquisition.AcquisitionsCommonList.AcquisitionListItem; import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler; -import org.collectionspace.services.acquisition.nuxeo.AcquisitionConstants; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; @@ -46,19 +45,19 @@ import org.slf4j.LoggerFactory; * $LastChangedDate: $ */ public class AcquisitionDocumentModelHandler - extends DocumentModelHandler { + extends DocumentModelHandler { private final Logger logger = LoggerFactory.getLogger(AcquisitionDocumentModelHandler.class); /** * acquisition is used to stash JAXB object to use when handle is called * for Action.CREATE, Action.UPDATE or Action.GET */ - private Acquisition acquisition; + private AcquisitionsCommon acquisition; /** * acquisitionList is stashed when handle is called * for ACTION.GET_ALL */ - private AcquisitionList acquisitionList; + private AcquisitionsCommonList acquisitionList; @Override public void prepare(Action action) throws Exception { @@ -66,20 +65,20 @@ public class AcquisitionDocumentModelHandler } /** - * getCommonObject get associated acquisition + * getCommonPart get associated acquisition * @return */ @Override - public Acquisition getCommonObject() { + public AcquisitionsCommon getCommonPart() { return acquisition; } /** - * setCommonObject set associated acquisition + * setCommonPart set associated acquisition * @param acquisition */ @Override - public void setCommonObject(Acquisition acquisition) { + public void setCommonPart(AcquisitionsCommon acquisition) { this.acquisition = acquisition; } @@ -88,53 +87,32 @@ public class AcquisitionDocumentModelHandler * @return */ @Override - public AcquisitionList getCommonObjectList() { + public AcquisitionsCommonList getCommonPartList() { return acquisitionList; } @Override - public void setCommonObjectList(AcquisitionList acquisitionList) { + public void setCommonPartList(AcquisitionsCommonList acquisitionList) { this.acquisitionList = acquisitionList; } @Override - public Acquisition extractCommonObject(DocumentWrapper wrapDoc) + public AcquisitionsCommon extractCommonPart(DocumentWrapper wrapDoc) throws Exception { - DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); - Acquisition acquisitionObject = new Acquisition(); - - //FIXME property get should be dynamically set using schema inspection - //so it does not require hard coding - - // acquisition core values - acquisitionObject.setAccessiondate((String)docModel.getPropertyValue( - getQProperty(AcquisitionJAXBSchema.ACCESSIONDATE))); - - return acquisitionObject; + throw new UnsupportedOperationException(); } @Override - public void fillCommonObject(Acquisition acquisitionObject, DocumentWrapper wrapDoc) throws Exception { - DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); - //FIXME property setter should be dynamically set using schema inspection - //so it does not require hard coding - - // a default title for the Dublin Core schema - docModel.setPropertyValue("dublincore:title", AcquisitionConstants.NUXEO_DC_TITLE); - - // acquisition core values - if(acquisitionObject.getAccessiondate() != null){ - docModel.setPropertyValue(getQProperty( - AcquisitionJAXBSchema.ACCESSIONDATE), acquisitionObject.getAccessiondate()); - } + public void fillCommonPart(AcquisitionsCommon acquisitionObject, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException(); } @Override - public AcquisitionList extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception { + public AcquisitionsCommonList extractCommonPartList(DocumentWrapper wrapDoc) throws Exception { DocumentModelList docList = (DocumentModelList) wrapDoc.getWrappedObject(); - AcquisitionList coList = new AcquisitionList(); - List list = coList.getAcquisitionListItem(); + AcquisitionsCommonList coList = new AcquisitionsCommonList(); + List list = coList.getAcquisitionListItem(); //FIXME: iterating over a long list of documents is not a long term //strategy...need to change to more efficient iterating in future @@ -142,11 +120,11 @@ public class AcquisitionDocumentModelHandler while(iter.hasNext()){ DocumentModel docModel = iter.next(); AcquisitionListItem listItem = new AcquisitionListItem(); - listItem.setAccessiondate((String)docModel.getPropertyValue( - getQProperty(AcquisitionJAXBSchema.ACCESSIONDATE))); + listItem.setAccessiondate((String) docModel.getProperty(getServiceContext().getCommonPartLabel(), + AcquisitionJAXBSchema.ACCESSIONDATE)); //need fully qualified context for URI String id = docModel.getId(); - listItem.setUri("/acquisitions/" + id); + listItem.setUri(getServiceContextPath() + id); listItem.setCsid(id); list.add(listItem); } @@ -155,23 +133,35 @@ public class AcquisitionDocumentModelHandler } @Override - public void fillCommonObjectList(AcquisitionList obj, DocumentWrapper wrapDoc) throws Exception { - throw new UnsupportedOperationException(); + public void fillAllParts(DocumentWrapper wrapDoc) throws Exception { + + super.fillAllParts(wrapDoc); + fillDublinCoreObject(wrapDoc); //dublincore might not be needed in future } + private void fillDublinCoreObject(DocumentWrapper wrapDoc) throws Exception { + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + //FIXME property setter should be dynamically set using schema inspection + //so it does not require hard coding + // a default title for the Dublin Core schema + docModel.setPropertyValue("dublincore:title", AcquisitionConstants.NUXEO_DC_TITLE); + } + + /* (non-Javadoc) * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#getDocumentType() */ public String getDocumentType() { - return AcquisitionConstants.NUXEO_DOCTYPE; + return AcquisitionConstants.NUXEO_DOCTYPE; } - + /** * getQProperty converts the given property to qualified schema property * @param prop * @return */ - private String getQProperty(String prop) { + @Override + public String getQProperty(String prop) { return AcquisitionConstants.NUXEO_SCHEMA_NAME + ":" + prop; } } diff --git a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionHandlerFactory.java b/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionHandlerFactory.java index ecb198567..163837336 100644 --- a/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionHandlerFactory.java +++ b/services/acquisition/service/src/main/java/org/collectionspace/services/acquisition/nuxeo/AcquisitionHandlerFactory.java @@ -23,7 +23,7 @@ */ package org.collectionspace.services.acquisition.nuxeo; -import org.collectionspace.services.common.NuxeoClientType; +import org.collectionspace.services.common.ClientType; import org.collectionspace.services.common.repository.DocumentHandler; /** @@ -45,7 +45,7 @@ public class AcquisitionHandlerFactory { } public DocumentHandler getHandler(String clientType) { - if(NuxeoClientType.JAVA.toString().equals(clientType)){ + if(ClientType.JAVA.toString().equals(clientType)){ return new AcquisitionDocumentModelHandler(); } diff --git a/services/authentication/client/src/test/java/org/collectionspace/services/authentication/client/AuthenticationServiceTest.java b/services/authentication/client/src/test/java/org/collectionspace/services/authentication/client/AuthenticationServiceTest.java index adcca32d1..9561cd40a 100644 --- a/services/authentication/client/src/test/java/org/collectionspace/services/authentication/client/AuthenticationServiceTest.java +++ b/services/authentication/client/src/test/java/org/collectionspace/services/authentication/client/AuthenticationServiceTest.java @@ -22,18 +22,18 @@ */ package org.collectionspace.services.authentication.client; -import java.util.ArrayList; -import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; import org.jboss.resteasy.client.ClientResponse; import org.testng.Assert; import org.testng.annotations.Test; -import org.collectionspace.services.collectionobject.CollectionObject; +import org.collectionspace.services.collectionobject.CollectionobjectsCommon; import org.collectionspace.services.client.CollectionObjectClient; import org.collectionspace.services.client.CollectionSpaceClient; +import org.collectionspace.services.client.test.AbstractServiceTest; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; +import org.jboss.resteasy.plugins.providers.multipart.OutputPart; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,15 +43,29 @@ import org.slf4j.LoggerFactory; * $LastChangedRevision: 434 $ * $LastChangedDate: 2009-07-28 14:34:15 -0700 (Tue, 28 Jul 2009) $ */ -public class AuthenticationServiceTest { +public class AuthenticationServiceTest extends AbstractServiceTest { - private String knownCollectionObjectId = null; + final String SERVICE_PATH_COMPONENT = "collectionobjects"; + private String knownResourceId = null; final Logger logger = LoggerFactory.getLogger(AuthenticationServiceTest.class); + @Override + public String getServicePathComponent() { + // @TODO Determine if it is possible to obtain this + // value programmatically. + // + // We set this in an annotation in the CollectionObjectProxy + // interface, for instance. We also set service-specific + // constants in each service module, which might also + // return this value. + return SERVICE_PATH_COMPONENT; + } + @Test - public void auth_createCollectionObject() { + @Override + public void create() { String identifier = this.createIdentifier(); - CollectionObject collectionObject = createCollectionObject(identifier); + MultipartOutput multipart = createCollectionObjectInstance(identifier); CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); if(!collectionObjectClient.isServerSecure()){ logger.warn("set -Dcspace.server.secure=true to run security tests"); @@ -64,22 +78,22 @@ public class AuthenticationServiceTest { collectionObjectClient.setupHttpClient(); collectionObjectClient.setProxy(); }catch(Exception e){ - logger.error("auth_createCollectionObject: caught " + e.getMessage()); + logger.error("create: caught " + e.getMessage()); return; } - ClientResponse res = collectionObjectClient.create(collectionObject); - verbose("auth_createCollectionObject: status = " + res.getStatus()); + ClientResponse res = collectionObjectClient.create(multipart); + verbose("create: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.CREATED.getStatusCode(), "expected " + Response.Status.CREATED.getStatusCode()); // Store the ID returned from this create operation for additional tests below. - knownCollectionObjectId = extractId(res); + knownResourceId = extractId(res); } - @Test(dependsOnMethods = {"auth_createCollectionObject"}) - public void auth_createCollectionObjectWithoutUser() { + @Test(dependsOnMethods = {"create"}) + public void createWithoutUser() { String identifier = this.createIdentifier(); - CollectionObject collectionObject = createCollectionObject(identifier); + MultipartOutput multipart = createCollectionObjectInstance(identifier); CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); if(!collectionObjectClient.isServerSecure()){ logger.warn("set -Dcspace.server.secure=true to run security tests"); @@ -92,19 +106,19 @@ public class AuthenticationServiceTest { collectionObjectClient.setupHttpClient(); collectionObjectClient.setProxy(); }catch(Exception e){ - logger.error("auth_createCollectionObjectWithoutUser: caught " + e.getMessage()); + logger.error("createWithoutUser: caught " + e.getMessage()); return; } - ClientResponse res = collectionObjectClient.create(collectionObject); - verbose("auth_createCollectionObjectWithoutUser: status = " + res.getStatus()); + ClientResponse res = collectionObjectClient.create(multipart); + verbose("createWithoutUser: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode()); } - @Test(dependsOnMethods = {"auth_createCollectionObjectWithoutUser"}) - public void auth_createCollectionObjectWithoutPassword() { + @Test(dependsOnMethods = {"createWithoutUser"}) + public void createWithoutPassword() { String identifier = this.createIdentifier(); - CollectionObject collectionObject = createCollectionObject(identifier); + MultipartOutput multipart = createCollectionObjectInstance(identifier); CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); if(!collectionObjectClient.isServerSecure()){ logger.warn("set -Dcspace.server.secure=true to run security tests"); @@ -117,19 +131,19 @@ public class AuthenticationServiceTest { collectionObjectClient.setupHttpClient(); collectionObjectClient.setProxy(); }catch(Exception e){ - logger.error("auth_createCollectionObjectWithoutPassword: caught " + e.getMessage()); + logger.error("createWithoutPassword: caught " + e.getMessage()); return; } - ClientResponse res = collectionObjectClient.create(collectionObject); - verbose("auth_createCollectionObjectWithoutPassword: status = " + res.getStatus()); + ClientResponse res = collectionObjectClient.create(multipart); + verbose("createWithoutPassword: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode()); } - @Test(dependsOnMethods = {"auth_createCollectionObjectWithoutPassword"}) - public void auth_createCollectionObjectWithIncorrectPassword() { + @Test(dependsOnMethods = {"createWithoutPassword"}) + public void createWithIncorrectPassword() { String identifier = this.createIdentifier(); - CollectionObject collectionObject = createCollectionObject(identifier); + MultipartOutput multipart = createCollectionObjectInstance(identifier); CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); if(!collectionObjectClient.isServerSecure()){ logger.warn("set -Dcspace.server.secure=true to run security tests"); @@ -142,19 +156,19 @@ public class AuthenticationServiceTest { collectionObjectClient.setupHttpClient(); collectionObjectClient.setProxy(); }catch(Exception e){ - logger.error("auth_createCollectionObjectWithIncorrectPassword: caught " + e.getMessage()); + logger.error("createWithIncorrectPassword: caught " + e.getMessage()); return; } - ClientResponse res = collectionObjectClient.create(collectionObject); - verbose("auth_createCollectionObjectWithIncorrectPassword: status = " + res.getStatus()); + ClientResponse res = collectionObjectClient.create(multipart); + verbose("createWithIncorrectPassword: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode()); } - @Test(dependsOnMethods = {"auth_createCollectionObjectWithoutPassword"}) - public void auth_createCollectionObjectWithoutUserPassword() { + @Test(dependsOnMethods = {"createWithoutPassword"}) + public void createWithoutUserPassword() { String identifier = this.createIdentifier(); - CollectionObject collectionObject = createCollectionObject(identifier); + MultipartOutput multipart = createCollectionObjectInstance(identifier); CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); if(!collectionObjectClient.isServerSecure()){ logger.warn("set -Dcspace.server.secure=true to run security tests"); @@ -167,19 +181,19 @@ public class AuthenticationServiceTest { collectionObjectClient.setupHttpClient(); collectionObjectClient.setProxy(); }catch(Exception e){ - logger.error("auth_createCollectionObjectWithoutUserPassword: caught " + e.getMessage()); + logger.error("createWithoutUserPassword: caught " + e.getMessage()); return; } - ClientResponse res = collectionObjectClient.create(collectionObject); - verbose("auth_createCollectionObjectWithoutUserPassword: status = " + res.getStatus()); + ClientResponse res = collectionObjectClient.create(multipart); + verbose("createWithoutUserPassword: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.FORBIDDEN.getStatusCode(), "expected " + Response.Status.FORBIDDEN.getStatusCode()); } - @Test(dependsOnMethods = {"auth_createCollectionObjectWithoutPassword"}) - public void auth_createCollectionObjectWithIncorrectUserPassword() { + @Test(dependsOnMethods = {"createWithoutPassword"}) + public void createWithIncorrectUserPassword() { String identifier = this.createIdentifier(); - CollectionObject collectionObject = createCollectionObject(identifier); + MultipartOutput multipart = createCollectionObjectInstance(identifier); CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); if(!collectionObjectClient.isServerSecure()){ logger.warn("set -Dcspace.server.secure=true to run security tests"); @@ -192,17 +206,18 @@ public class AuthenticationServiceTest { collectionObjectClient.setupHttpClient(); collectionObjectClient.setProxy(); }catch(Exception e){ - logger.error("auth_createCollectionObjectWithIncorrectUserPassword: caught " + e.getMessage()); + logger.error("createWithIncorrectUserPassword: caught " + e.getMessage()); return; } - ClientResponse res = collectionObjectClient.create(collectionObject); - verbose("auth_createCollectionObjectWithIncorrectUserPassword: status = " + res.getStatus()); + ClientResponse res = collectionObjectClient.create(multipart); + verbose("createWithIncorrectUserPassword: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode(), "expected " + Response.Status.UNAUTHORIZED.getStatusCode()); } - @Test(dependsOnMethods = {"auth_createCollectionObjectWithIncorrectUserPassword"}) - public void auth_deleteCollectionObject() { + @Override + @Test(dependsOnMethods = {"createWithIncorrectUserPassword"}) + public void delete() { CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); collectionObjectClient = new CollectionObjectClient(); if(!collectionObjectClient.isServerSecure()){ @@ -216,12 +231,12 @@ public class AuthenticationServiceTest { collectionObjectClient.setupHttpClient(); collectionObjectClient.setProxy(); }catch(Exception e){ - logger.error("auth_deleteCollectionObject: caught " + e.getMessage()); + logger.error("deleteCollectionObject: caught " + e.getMessage()); return; } - verbose("Calling deleteCollectionObject:" + knownCollectionObjectId); - ClientResponse res = collectionObjectClient.delete(knownCollectionObjectId); - verbose("auth_deleteCollectionObject: status = " + res.getStatus()); + verbose("Calling deleteCollectionObject:" + knownResourceId); + ClientResponse res = collectionObjectClient.delete(knownResourceId); + verbose("deleteCollectionObject: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.OK.getStatusCode(), "expected " + Response.Status.OK.getStatusCode()); } @@ -229,53 +244,73 @@ public class AuthenticationServiceTest { // --------------------------------------------------------------- // Utility methods used by tests above // --------------------------------------------------------------- - private CollectionObject createCollectionObject(String identifier) { - CollectionObject collectionObject = createCollectionObject("objectNumber-" + identifier, + private MultipartOutput createCollectionObjectInstance(String identifier) { + return createCollectionObjectInstance("objectNumber-" + identifier, "objectName-" + identifier); - - return collectionObject; } - private CollectionObject createCollectionObject(String objectNumber, String objectName) { - CollectionObject collectionObject = new CollectionObject(); + private MultipartOutput createCollectionObjectInstance(String objectNumber, String objectName) { + CollectionobjectsCommon collectionObject = new CollectionobjectsCommon(); collectionObject.setObjectNumber(objectNumber); collectionObject.setObjectName(objectName); + MultipartOutput multipart = new MultipartOutput(); + OutputPart commonPart = multipart.addPart(collectionObject, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", getCommonPartName()); - return collectionObject; + verbose("to be created, collectionobject common ", collectionObject, CollectionobjectsCommon.class); + return multipart; } - private String extractId(ClientResponse res) { - MultivaluedMap mvm = res.getMetadata(); - String uri = (String) ((ArrayList) mvm.get("Location")).get(0); - verbose("extractId:uri=" + uri); - String[] segments = uri.split("/"); - String id = segments[segments.length - 1]; - verbose("id=" + id); - return id; + @Override + public void createList() { } - private void verbose(String msg) { - if(logger.isInfoEnabled()){ - logger.debug(msg); - } + @Override + public void createWithEmptyEntityBody() { } - private void verbose(String msg, Object o, Class clazz) { - try{ - verbose(msg); - JAXBContext jc = JAXBContext.newInstance(clazz); - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, - Boolean.TRUE); - m.marshal(o, System.out); - }catch(Exception e){ - e.printStackTrace(); - } + @Override + public void createWithMalformedXml() { + } + + @Override + public void createWithWrongXmlSchema() { + } + + @Override + public void read() { + } + + @Override + public void readNonExistent() { + } + + @Override + public void readList() { + } + + @Override + public void update() { + } + + @Override + public void updateWithEmptyEntityBody() { + } + + @Override + public void updateWithMalformedXml() { + } + + @Override + public void updateWithWrongXmlSchema() { + } + + @Override + public void updateNonExistent() { } - private String createIdentifier() { - long identifier = System.currentTimeMillis(); - return Long.toString(identifier); + @Override + public void deleteNonExistent() { } } diff --git a/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java b/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java index 63dea9bde..0391baf5e 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java +++ b/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java @@ -23,21 +23,22 @@ */ package org.collectionspace.services.client.test; -import java.io.IOException; -import java.io.UnsupportedEncodingException; +import java.io.ByteArrayInputStream; import java.util.ArrayList; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; import org.collectionspace.services.client.TestServiceClient; -import org.collectionspace.services.client.test.ServiceRequestType; import org.jboss.resteasy.client.ClientRequest; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.InputPart; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,18 +51,14 @@ import org.slf4j.LoggerFactory; public abstract class AbstractServiceTest implements ServiceTest { final Logger logger = LoggerFactory.getLogger(AbstractServiceTest.class); - // A base-level client, used (only) to obtain the base service URL. private static final TestServiceClient serviceClient = new TestServiceClient(); - // A resource identifier believed to be non-existent in actual use, // used when testing service calls that reference non-existent resources. protected final String NON_EXISTENT_ID = createNonExistentIdentifier(); - // The HTTP status code expected to be returned in the response, // from a request made to a service (where relevant). int EXPECTED_STATUS_CODE = 0; - // The generic type of service request being tested (e.g. CREATE, UPDATE, DELETE). // // This makes it possible to check behavior specific to that type of request, @@ -69,31 +66,28 @@ public abstract class AbstractServiceTest implements ServiceTest { // // Note that the default value is set to a guard value. protected ServiceRequestType REQUEST_TYPE = ServiceRequestType.NON_EXISTENT; - // Static data to be submitted in various tests protected final static String XML_DECLARATION = - ""; - + ""; // Note: this constant is intentionally missing its last angle bracket. protected final static String MALFORMED_XML_DATA = - XML_DECLARATION + - "wrong schema contentswrong schema contentswrong schema contents"; + XML_DECLARATION + + "wrong schema contents"; // --------------------------------------------------------------- // CRUD tests : CREATE tests // --------------------------------------------------------------- - // Success outcomes - @Override - public abstract void create(); - + public void create() { + + } + protected void setupCreate() { - clearSetup(); + clearSetup("Create"); // Expected status code: 201 Created EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); // Type of service request being tested @@ -102,16 +96,14 @@ public abstract class AbstractServiceTest implements ServiceTest { @Override public abstract void createList(); - - // No setup required for createList() + // No setup required for createList() // Failure outcomes - @Override public abstract void createWithEmptyEntityBody(); protected void setupCreateWithEmptyEntityBody() { - clearSetup(); + clearSetup("CreateWithEmptyEntityBody"); EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.CREATE; } @@ -120,7 +112,7 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void createWithMalformedXml(); protected void setupCreateWithMalformedXml() { - clearSetup(); + clearSetup("CreateWithMalformedXml"); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.CREATE; @@ -130,87 +122,74 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void createWithWrongXmlSchema(); protected void setupCreateWithWrongXmlSchema() { - clearSetup(); + clearSetup("CreateWithWrongXmlSchema"); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.CREATE; } - // --------------------------------------------------------------- // CRUD tests : READ tests // --------------------------------------------------------------- - // Success outcomes - @Override public abstract void read(); protected void setupRead() { - clearSetup(); + clearSetup("Read"); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.READ; } // Failure outcomes - @Override public abstract void readNonExistent(); protected void setupReadNonExistent() { - clearSetup(); + clearSetup("ReadNonExistent"); // Expected status code: 404 Not Found EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); REQUEST_TYPE = ServiceRequestType.READ; } - // --------------------------------------------------------------- // CRUD tests : READ (list, or multiple) tests // --------------------------------------------------------------- - // Success outcomes - @Override public abstract void readList(); protected void setupReadList() { - clearSetup(); + clearSetup("ReadList"); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.READ_LIST; } // Failure outcomes - // None tested at present. - - // --------------------------------------------------------------- // CRUD tests : UPDATE tests // --------------------------------------------------------------- - // Success outcomes // ---------------- - @Override public abstract void update(); protected void setupUpdate() { - clearSetup(); + clearSetup("Update"); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; } // Failure outcomes - @Override public abstract void updateWithEmptyEntityBody(); protected void setupUpdateWithEmptyEntityBody() { - clearSetup(); + clearSetup("UpdateWithEmptyEntityBody"); EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; } @@ -219,7 +198,7 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void updateWithMalformedXml(); protected void setupUpdateWithMalformedXml() { - clearSetup(); + clearSetup("UpdateWithMalformedXml"); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; @@ -229,7 +208,7 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void updateWithWrongXmlSchema(); protected void setupUpdateWithWrongXmlSchema() { - clearSetup(); + clearSetup("UpdateWithWrongXmlSchema"); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; @@ -239,69 +218,70 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void updateNonExistent(); protected void setupUpdateNonExistent() { - clearSetup(); + clearSetup("UpdateNonExistent"); // Expected status code: 404 Not Found EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; } - // --------------------------------------------------------------- // CRUD tests : DELETE tests // --------------------------------------------------------------- - // Success outcomes - @Override public abstract void delete(); - + protected void setupDelete() { - clearSetup(); + clearSetup("Delete"); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.DELETE; } - + // Failure outcomes - @Override public abstract void deleteNonExistent(); protected void setupDeleteNonExistent() { - clearSetup(); + clearSetup("DeleteNonExistent"); // Expected status code: 404 Not Found EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); REQUEST_TYPE = ServiceRequestType.DELETE; } - // --------------------------------------------------------------- // Abstract utility methods // // Must be implemented by classes that extend // this abstract base class. // --------------------------------------------------------------- - /** * Returns the URL path component of the service. * * This component will follow directly after the * base path, if any. */ - protected abstract String getServicePathComponent(); + @Override + public abstract String getServicePathComponent(); + @Override + public String getCommonPartName() { + return getServicePathComponent() + "-common"; + } // --------------------------------------------------------------- // Utility methods // --------------------------------------------------------------- - /** * Reinitializes setup values, to help expose any unintended reuse * of those values between tests. */ - protected void clearSetup() { + protected void clearSetup(String testName) { EXPECTED_STATUS_CODE = 0; REQUEST_TYPE = ServiceRequestType.NON_EXISTENT; + logger.debug("========================================================"); + logger.debug(" Test = " + testName); + logger.debug("========================================================"); } /** @@ -317,11 +297,10 @@ public abstract class AbstractServiceTest implements ServiceTest { * @return An error message. */ protected String invalidStatusCodeMessage(ServiceRequestType requestType, int statusCode) { - return - "Status code '" + statusCode + "' in response is NOT within the expected set: " + - requestType.validStatusCodesAsString(); + return "Status code '" + statusCode + "' in response is NOT within the expected set: " + + requestType.validStatusCodesAsString(); } - + /** * Returns the root URL for a service. * @@ -330,7 +309,7 @@ public abstract class AbstractServiceTest implements ServiceTest { * * @return The root URL for a service. */ - protected String getServiceRootURL() { + protected String getServiceRootURL() { return serviceClient.getBaseURL() + getServicePathComponent(); } @@ -359,24 +338,24 @@ public abstract class AbstractServiceTest implements ServiceTest { */ protected int submitRequest(String method, String url) { int statusCode = 0; - try { + try{ ClientRequest request = new ClientRequest(url); - if (method.equals(javax.ws.rs.HttpMethod.DELETE)) { + if(method.equals(javax.ws.rs.HttpMethod.DELETE)){ ClientResponse res = request.delete(); - statusCode = res.getStatus(); - } else if (method.equals(javax.ws.rs.HttpMethod.GET)) { + statusCode = res.getStatus(); + }else if(method.equals(javax.ws.rs.HttpMethod.GET)){ ClientResponse res = request.get(); - statusCode = res.getStatus(); - } else { + statusCode = res.getStatus(); + }else{ // Do nothing - leave status code at default value. } - } catch (Exception e) { - logger.error( - "Exception during HTTP " + method + " request to " + url + ":", - e); + }catch(Exception e){ + logger.error( + "Exception during HTTP " + method + " request to " + url + ":", + e); } return statusCode; - } + } /** * Submits an HTTP request to a specified URL, with the submitted @@ -394,31 +373,29 @@ public abstract class AbstractServiceTest implements ServiceTest { * @return The status code received in the HTTP response. */ protected int submitRequest(String method, String url, - String mediaType, String entityStr) { + String mediaType, String entityStr) { int statusCode = 0; - try { + try{ ClientRequest request = new ClientRequest(url); request.body(mediaType, entityStr); - if (method.equals(javax.ws.rs.HttpMethod.POST)) { + if(method.equals(javax.ws.rs.HttpMethod.POST)){ ClientResponse res = request.post(java.lang.String.class); - statusCode = res.getStatus(); - } else if (method.equals(javax.ws.rs.HttpMethod.PUT)) { + statusCode = res.getStatus(); + }else if(method.equals(javax.ws.rs.HttpMethod.PUT)){ ClientResponse res = request.put(java.lang.String.class); - statusCode = res.getStatus(); - } else { + statusCode = res.getStatus(); + }else{ // Do nothing - leave status code at default value. } - } catch (Exception e) { - logger.error( - "Exception during HTTP " + method + " request to " + url + ":", - e); + }catch(Exception e){ + logger.error( + "Exception during HTTP " + method + " request to " + url + ":", + e); } return statusCode; - } + } // @TODO Add Javadoc comments to all methods requiring them, below. - - protected String extractId(ClientResponse res) { MultivaluedMap mvm = res.getMetadata(); String uri = (String) ((ArrayList) mvm.get("Location")).get(0); @@ -430,7 +407,7 @@ public abstract class AbstractServiceTest implements ServiceTest { } protected void verbose(String msg) { - if (logger.isDebugEnabled()) { + if(logger.isDebugEnabled()){ logger.debug(msg); } } @@ -463,7 +440,40 @@ public abstract class AbstractServiceTest implements ServiceTest { protected String createNonExistentIdentifier() { return Long.toString(Long.MAX_VALUE); } - + + protected Object extractPart(MultipartInput input, String label, Class clazz) throws Exception { + Object obj = null; + for(InputPart part : input.getParts()){ + String partLabel = part.getHeaders().getFirst("label"); + if(label.equalsIgnoreCase(partLabel)){ + String partStr = part.getBodyAsString(); + verbose("extracted part str=\n" + partStr); + obj = part.getBody(clazz, null); + verbose("extracted part obj=\n", obj, clazz); + break; + } + } + return obj; + } + + protected Object getPartObject(String partStr, Class clazz) throws JAXBException { + JAXBContext jc = JAXBContext.newInstance(clazz); + ByteArrayInputStream bais = null; + Object obj = null; + try{ + bais = new ByteArrayInputStream(partStr.getBytes()); + Unmarshaller um = jc.createUnmarshaller(); + obj = um.unmarshal(bais); + }finally{ + if(bais != null){ + try{ + bais.close(); + }catch(Exception e){ + } + } + } + return obj; + } } diff --git a/services/client/src/main/java/org/collectionspace/services/client/test/ServiceTest.java b/services/client/src/main/java/org/collectionspace/services/client/test/ServiceTest.java index 8305cae34..8f54216f8 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/test/ServiceTest.java +++ b/services/client/src/main/java/org/collectionspace/services/client/test/ServiceTest.java @@ -29,6 +29,21 @@ package org.collectionspace.services.client.test; */ public interface ServiceTest { + + /** + * Returns the URL path component of the service. + * + * This component will follow directly after the + * base path, if any. + */ + public String getServicePathComponent(); + + /** + * getCommonPartName get common part name for the service request + * @return + */ + public String getCommonPartName(); + // --------------------------------------------------------------- // CRUD tests : CREATE tests // --------------------------------------------------------------- @@ -40,7 +55,7 @@ public interface ServiceTest { * * Relied upon by 'read', 'update' and 'delete' tests, below. */ - public void create(); + public void create(); /** * Tests creation of a list of two or more new resources by repeatedly @@ -54,23 +69,23 @@ public interface ServiceTest { /** * Tests creation of a resource by submitting - * an empty entity body (aka empty payload). + * an empty entity body (aka empty payload). */ public void createWithEmptyEntityBody(); /** * Tests creation of a resource by submitting - * a representation with malformed XML data. + * a representation with malformed XML data. */ public void createWithMalformedXml(); /** * Tests creation of a resource by submitting * a representation in the wrong XML schema - * (e.g. not matching the object's schema). + * (e.g. not matching the object's schema). */ public void createWithWrongXmlSchema(); - + // @TODO If feasible, implement a negative (failure) // test for creation of duplicate resources. @@ -80,9 +95,9 @@ public interface ServiceTest { // --------------------------------------------------------------- // Success outcomes - + /** - * Tests reading (i.e. retrieval) of a resource. + * Tests reading (i.e. retrieval) of a resource. */ public void read(); @@ -93,7 +108,7 @@ public interface ServiceTest { * resource, whose resource identifier does not exist * at the specified URL. */ - public void readNonExistent(); + public void readNonExistent(); // --------------------------------------------------------------- @@ -106,13 +121,13 @@ public interface ServiceTest { * Tests reading (i.e. retrieval) of a list of * multiple resources. */ - public void readList(); + public void readList(); // If feasible, implement a test for reading // an empty list returned by the service. // Failure outcomes - + // If feasible, implement a negative (failure) test // of handling of unrecognized query parameters // (e.g. other than filtering or chunking parameters, etc. @@ -126,7 +141,7 @@ public interface ServiceTest { // ---------------- /** - * Tests updating the content of a resource. + * Tests updating the content of a resource. */ public void update(); @@ -139,16 +154,16 @@ public interface ServiceTest { public void updateWithEmptyEntityBody(); /** - * Tests updating the content of a resource + * Tests updating the content of a resource * by submitting a representation with malformed - * XML data. + * XML data. */ public void updateWithMalformedXml(); /** * Tests updating the content of a resource * by submitting a representation in the wrong - * XML schema (e.g. not matching the object's schema). + * XML schema (e.g. not matching the object's schema). */ public void updateWithWrongXmlSchema(); @@ -168,16 +183,16 @@ public interface ServiceTest { /** * Tests deleting a resource. */ - public void delete(); - + public void delete(); + // Failure outcomes - + /** * Tests deleting a non-existent resource, whose resource * identifier does not exist at the specified URL. */ public void deleteNonExistent(); - + } diff --git a/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/OSGI-INF/core-types-contrib.xml b/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/OSGI-INF/core-types-contrib.xml index 72aa5ef19..8ab4cb2e0 100644 --- a/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/OSGI-INF/core-types-contrib.xml +++ b/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/OSGI-INF/core-types-contrib.xml @@ -1,13 +1,15 @@ - - - - - - - - - - + + + + + + + + + + + + diff --git a/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobject.xsd b/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-common.xsd similarity index 100% rename from services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobject.xsd rename to services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-common.xsd diff --git a/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-naturalhistory.xsd b/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-naturalhistory.xsd new file mode 100644 index 000000000..25aceab31 --- /dev/null +++ b/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects-naturalhistory.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/services/collectionobject/3rdparty/pom.xml~ b/services/collectionobject/3rdparty/pom.xml~ new file mode 100644 index 000000000..ce7ce10bd --- /dev/null +++ b/services/collectionobject/3rdparty/pom.xml~ @@ -0,0 +1,36 @@ + + + 4.0.0 + + + org.collectionspace.services.collectionobject + org.collectionspace.services + 1.0 + + + org.collectionspace.services.collectionobject.doctype + jar + collectionobject.doctype + + CollectionObject Nuxeo document type + + + 5.2-SNAPSHOT + 1.5-SNAPSHOT + + + + org.nuxeo.ecm.core + nuxeo-core-schema + ${nuxeo.version.1.5} + + + org.nuxeo.ecm.platform + nuxeo-platform-types-core + ${nuxeo.version.5.2} + + + + diff --git a/services/collectionobject/client/pom.xml b/services/collectionobject/client/pom.xml index ffa4ab470..b9135886e 100644 --- a/services/collectionobject/client/pom.xml +++ b/services/collectionobject/client/pom.xml @@ -55,7 +55,7 @@ org.jboss.resteasy resteasy-jaxrs - 1.0.2.GA + 1.1.GA @@ -67,12 +67,12 @@ org.jboss.resteasy resteasy-jaxb-provider - 1.0.2.GA + 1.1.GA org.jboss.resteasy resteasy-multipart-provider - 1.0.2.GA + 1.1.GA commons-httpclient diff --git a/services/collectionobject/client/received.xml b/services/collectionobject/client/received.xml new file mode 100644 index 000000000..f8d838227 --- /dev/null +++ b/services/collectionobject/client/received.xml @@ -0,0 +1,5 @@ + + +objectNumber-1252961305700 +objectName-1252961305700 + diff --git a/services/collectionobject/client/received.xml~ b/services/collectionobject/client/received.xml~ new file mode 100644 index 000000000..f69b0eb65 --- /dev/null +++ b/services/collectionobject/client/received.xml~ @@ -0,0 +1,6 @@ + + +objectNumber-1252960223850 +objectName-1252960223850 + diff --git a/services/collectionobject/client/sent.xml b/services/collectionobject/client/sent.xml new file mode 100644 index 000000000..eace94d36 --- /dev/null +++ b/services/collectionobject/client/sent.xml @@ -0,0 +1,6 @@ + + +objectNumber-1252960222412 +objectName-1252960222412 + + diff --git a/services/collectionobject/client/sent.xml~ b/services/collectionobject/client/sent.xml~ new file mode 100644 index 000000000..d69827696 --- /dev/null +++ b/services/collectionobject/client/sent.xml~ @@ -0,0 +1,3 @@ +objectNumber-1252960222412objectName-1252960222412 + diff --git a/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectClient.java b/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectClient.java index c44e452b9..ea9c5b865 100644 --- a/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectClient.java +++ b/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectClient.java @@ -2,12 +2,13 @@ package org.collectionspace.services.client; import javax.ws.rs.core.Response; -import org.collectionspace.services.collectionobject.CollectionObject; -import org.collectionspace.services.collectionobject.CollectionObjectList; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList; import org.jboss.resteasy.client.ProxyFactory; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.spi.ResteasyProviderFactory; /** @@ -48,10 +49,11 @@ public class CollectionObjectClient extends BaseServiceClient { /** * @return - * @see org.collectionspace.hello.client.CollectionObjectProxy#getCollectionObject() + * @see org.collectionspace.hello.client.CollectionObjectProxy#readList() */ - public ClientResponse readList() { + public ClientResponse readList() { return collectionObjectProxy.readList(); + } /** @@ -59,27 +61,27 @@ public class CollectionObjectClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.CollectionObjectProxy#getCollectionObject(java.lang.String) */ - public ClientResponse read(String csid) { + public ClientResponse read(String csid) { return collectionObjectProxy.read(csid); } /** * @param collectionobject * @return - * @see org.collectionspace.hello.client.CollectionObjectProxy#createCollectionObject(org.collectionspace.hello.CollectionObject) + * @see org.collectionspace.hello.client.CollectionObjectProxy#create(org.collectionspace.services.collectionobject.CollectionobjectsCommon) */ - public ClientResponse create(CollectionObject collectionObject) { - return collectionObjectProxy.create(collectionObject); + public ClientResponse create(MultipartOutput multipart) { + return collectionObjectProxy.create(multipart); } /** * @param csid * @param collectionobject * @return - * @see org.collectionspace.hello.client.CollectionObjectProxy#updateCollectionObject(java.lang.Long, org.collectionspace.hello.CollectionObject) + * @see org.collectionspace.hello.client.CollectionObjectProxy#updateCollectionObject(java.lang.Long, org.collectionspace.services.collectionobject.CollectionobjectsCommon) */ - public ClientResponse update(String csid, CollectionObject collectionObject) { - return collectionObjectProxy.update(csid, collectionObject); + public ClientResponse update(String csid, MultipartOutput multipart) { + return collectionObjectProxy.update(csid, multipart); } /** diff --git a/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectProxy.java b/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectProxy.java index a324f1cc0..e6fcb8ec1 100644 --- a/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectProxy.java +++ b/services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectProxy.java @@ -10,37 +10,40 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Response; -import org.collectionspace.services.collectionobject.CollectionObject; -import org.collectionspace.services.collectionobject.CollectionObjectList; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; + /** * @version $Revision:$ */ @Path("/collectionobjects/") -@Produces({"application/xml"}) -@Consumes({"application/xml"}) +@Produces({"multipart/mixed"}) +@Consumes({"multipart/mixed"}) public interface CollectionObjectProxy { @GET - ClientResponse readList(); + @Produces({"application/xml"}) + ClientResponse readList(); //(C)reate @POST - ClientResponse create(CollectionObject co); + ClientResponse create(MultipartOutput multipart); //(R)ead @GET @Path("/{csid}") - ClientResponse read(@PathParam("csid") String csid); + ClientResponse read(@PathParam("csid") String csid); //(U)pdate @PUT @Path("/{csid}") - ClientResponse update(@PathParam("csid") String csid, CollectionObject co); + ClientResponse update(@PathParam("csid") String csid, MultipartOutput multipart); //(D)elete @DELETE @Path("/{csid}") ClientResponse delete(@PathParam("csid") String csid); -} \ No newline at end of file +} diff --git a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java index 8ea4c8488..a8e499905 100644 --- a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java +++ b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java @@ -20,21 +20,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.collectionspace.services.client.test; import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; import org.collectionspace.services.client.CollectionObjectClient; -import org.collectionspace.services.client.test.ServiceRequestType; -import org.collectionspace.services.collectionobject.CollectionObject; -import org.collectionspace.services.collectionobject.CollectionObjectList; +import org.collectionspace.services.collectionobject.CollectionobjectsCommon; +import org.collectionspace.services.collectionobject.domain.naturalhistory.CollectionObjectNaturalhistory; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; +import org.jboss.resteasy.plugins.providers.multipart.OutputPart; import org.testng.Assert; import org.testng.annotations.Test; @@ -51,13 +52,11 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { private CollectionObjectClient client = new CollectionObjectClient(); final String SERVICE_PATH_COMPONENT = "collectionobjects"; private String knownResourceId = null; - + // --------------------------------------------------------------- // CRUD tests : CREATE tests // --------------------------------------------------------------- - // Success outcomes - @Override @Test public void create() { @@ -69,9 +68,10 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. String identifier = createIdentifier(); - CollectionObject collectionObject = - createCollectionObjectInstance(identifier); - ClientResponse res = client.create(collectionObject); + + MultipartOutput multipart = createCollectionObjectInstance(identifier); + ClientResponse res = client.create(multipart); + int statusCode = res.getStatus(); // Check the status code of the response: does it match @@ -82,12 +82,13 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Does it exactly match the expected status code? verbose("create: status = " + statusCode); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); // Store the ID returned from this create operation // for additional tests below. knownResourceId = extractId(res); + verbose("create: knownResourceId=" + knownResourceId); } @Override @@ -99,7 +100,6 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { } // Failure outcomes - // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. public void createWithEmptyEntityBody() {} @@ -177,26 +177,33 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // --------------------------------------------------------------- // CRUD tests : READ tests // --------------------------------------------------------------- - // Success outcomes - @Override @Test(dependsOnMethods = {"create"}) public void read() { - + // Perform setup. setupRead(); // Submit the request to the service and store the response. - ClientResponse res = client.read(knownResourceId); + ClientResponse res = client.read(knownResourceId); int statusCode = res.getStatus(); - + // Check the status code of the response: does it match // the expected response(s)? verbose("read: status = " + statusCode); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + //FIXME: remove the following try catch once Aron fixes signatures + try{ + MultipartInput input = (MultipartInput) res.getEntity(); + CollectionobjectsCommon collectionObject = (CollectionobjectsCommon) extractPart(input, + getCommonPartName(), CollectionobjectsCommon.class); + Assert.assertNotNull(collectionObject); + }catch(Exception e){ + throw new RuntimeException(e); + } } // Failure outcomes @@ -207,52 +214,50 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Perform setup. setupReadNonExistent(); - + // Submit the request to the service and store the response. - ClientResponse res = client.read(NON_EXISTENT_ID); + ClientResponse res = client.read(NON_EXISTENT_ID); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("readNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - // --------------------------------------------------------------- // CRUD tests : READ_LIST tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = {"createList"}) + @Test(dependsOnMethods = {"createList", "read"}) public void readList() { - // Perform setup. setupReadList(); // Submit the request to the service and store the response. - ClientResponse res = client.readList(); - CollectionObjectList list = res.getEntity(); + ClientResponse res = client.readList(); + CollectionobjectsCommonList list = res.getEntity(); + int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("readList: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); // Optionally output additional data about list members for debugging. boolean iterateThroughList = false; if (iterateThroughList && logger.isDebugEnabled()) { - List items = + List items = list.getCollectionObjectListItem(); int i = 0; - for(CollectionObjectList.CollectionObjectListItem item : items){ + + for(CollectionobjectsCommonList.CollectionObjectListItem item : items){ verbose("readList: list-item[" + i + "] csid=" + item.getCsid()); verbose("readList: list-item[" + i + "] objectNumber=" + @@ -262,59 +267,63 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { i++; } } - } // Failure outcomes - // None at present. - - // --------------------------------------------------------------- // CRUD tests : UPDATE tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = {"create"}) + @Test(dependsOnMethods = {"read"}) public void update() { - + // Perform setup. setupUpdate(); - - // Retrieve an existing resource that we can update. - ClientResponse res = client.read(knownResourceId); - verbose("read: status = " + res.getStatus()); - Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); - CollectionObject collectionObject = res.getEntity(); - verbose("Got object to update with ID: " + knownResourceId, - collectionObject, CollectionObject.class); - - // Update the content of this resource. - collectionObject.setObjectNumber("updated-" + - collectionObject.getObjectNumber()); - collectionObject.setObjectName("updated-" + - collectionObject.getObjectName()); - - // Submit the request to the service and store the response. - res = client.update(knownResourceId, collectionObject); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("update: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - - // Check the contents of the response: does it match - // what was submitted? - CollectionObject updatedObject = res.getEntity(); - verbose("update: ", updatedObject, CollectionObject.class); - Assert.assertEquals(updatedObject.getObjectName(), - collectionObject.getObjectName(), - "Data in updated object did not match submitted data."); + try{ //ideally, just remove try-catch and let the exception bubble up + // Retrieve an existing resource that we can update. + ClientResponse res = + client.read(knownResourceId); + verbose("update: read status = " + res.getStatus()); + Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); + + verbose("got object to update with ID: " + knownResourceId); + MultipartInput input = (MultipartInput) res.getEntity(); + CollectionobjectsCommon collectionObject = (CollectionobjectsCommon) extractPart(input, + getCommonPartName(), CollectionobjectsCommon.class); + Assert.assertNotNull(collectionObject); + + // Update the content of this resource. + collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber()); + collectionObject.setObjectName("updated-" + collectionObject.getObjectName()); + verbose("updated object", collectionObject, CollectionobjectsCommon.class); + // Submit the request to the service and store the response. + MultipartOutput output = new MultipartOutput(); + OutputPart commonPart = output.addPart(collectionObject, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", getCommonPartName()); + + res = client.update(knownResourceId, output); + int statusCode = res.getStatus(); + // Check the status code of the response: does it match the expected response(s)? + verbose("update: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + + input = (MultipartInput) res.getEntity(); + CollectionobjectsCommon updatedCollectionObject = + (CollectionobjectsCommon) extractPart(input, + getCommonPartName(), CollectionobjectsCommon.class); + Assert.assertNotNull(updatedCollectionObject); + + Assert.assertEquals(updatedCollectionObject.getObjectName(), + collectionObject.getObjectName(), + "Data in updated object did not match submitted data."); + }catch(Exception e){ + e.printStackTrace(); + } } // Failure outcomes @@ -327,6 +336,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { /* @Override + @Test(dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithEmptyEntityBody() { @@ -402,29 +412,28 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. // Note: The ID used in this 'create' call may be arbitrary. - // The only relevant ID may be the one used in update(), below. - CollectionObject collectionObject = createCollectionObjectInstance(NON_EXISTENT_ID); - ClientResponse res = - client.update(NON_EXISTENT_ID, collectionObject); + + // The only relevant ID may be the one used in updateCollectionObject(), below. + MultipartOutput multipart = createCollectionObjectInstance(NON_EXISTENT_ID); + ClientResponse res = + client.update(NON_EXISTENT_ID, multipart); + int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("updateNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } // --------------------------------------------------------------- // CRUD tests : DELETE tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = - {"create", "read", "update"}) + @Test(dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"}) public void delete() { // Perform setup. @@ -438,12 +447,11 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // the expected response(s)? verbose("delete: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } // Failure outcomes - @Override @Test(dependsOnMethods = {"delete"}) public void deleteNonExistent() { @@ -459,15 +467,13 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // the expected response(s)? verbose("deleteNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - // --------------------------------------------------------------- // Utility tests : tests of code used in tests above // --------------------------------------------------------------- - /** * Tests the code for manually submitting data that is used by several * of the methods above. @@ -482,7 +488,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { String method = ServiceRequestType.READ.httpMethodName(); String url = getResourceURL(knownResourceId); int statusCode = submitRequest(method, url); - + // Check the status code of the response: does it match // the expected response(s)? verbose("testSubmitRequest: url=" + url + " status=" + statusCode); @@ -493,7 +499,6 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // --------------------------------------------------------------- // Utility methods used by tests above // --------------------------------------------------------------- - @Override public String getServicePathComponent() { // @TODO Determine if it is possible to obtain this @@ -505,22 +510,36 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // return this value. return SERVICE_PATH_COMPONENT; } - - private CollectionObject createCollectionObjectInstance(String identifier) { - CollectionObject collectionObject = - createCollectionObjectInstance( - "objectNumber-" + identifier, - "objectName-" + identifier); - return collectionObject; + + private MultipartOutput createCollectionObjectInstance(String identifier) { + return createCollectionObjectInstance("objectNumber-" + identifier, + "objectName-" + identifier); } - private CollectionObject createCollectionObjectInstance( - String objectNumber, String objectName) { - CollectionObject collectionObject = new CollectionObject(); + private MultipartOutput createCollectionObjectInstance(String objectNumber, String objectName) { + CollectionobjectsCommon collectionObject = new CollectionobjectsCommon(); + collectionObject.setObjectNumber(objectNumber); collectionObject.setObjectName(objectName); - return collectionObject; + MultipartOutput multipart = new MultipartOutput(); + OutputPart commonPart = multipart.addPart(collectionObject, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", getCommonPartName()); + + verbose("to be created, collectionobject common ", collectionObject, CollectionobjectsCommon.class); + + CollectionObjectNaturalhistory conh = new CollectionObjectNaturalhistory(); + conh.setNhString("test-string"); + conh.setNhInt(999); + conh.setNhLong(9999); + OutputPart nhPart = multipart.addPart(conh, MediaType.APPLICATION_XML_TYPE); + nhPart.getHeaders().add("label", getNHPartName()); + + verbose("to be created, collectionobject nhistory", conh, CollectionObjectNaturalhistory.class); + return multipart; + + } + + private String getNHPartName() { + return "collectionobjects-naturalhistory"; } - - } diff --git a/services/collectionobject/client/test.xml b/services/collectionobject/client/test.xml new file mode 100644 index 000000000..b407eab5f --- /dev/null +++ b/services/collectionobject/client/test.xml @@ -0,0 +1,8 @@ + + +objectNumber-1252955075364 +objectName-1252955075364 + diff --git a/services/collectionobject/jaxb/pom.xml b/services/collectionobject/jaxb/pom.xml index 15d479b37..6dd085c3f 100644 --- a/services/collectionobject/jaxb/pom.xml +++ b/services/collectionobject/jaxb/pom.xml @@ -56,7 +56,7 @@ com.sun.xml.bind jaxb-impl - 2.1.2 + 2.1.9 diff --git a/services/collectionobject/jaxb/src/main/resources/collectionobject.xsd b/services/collectionobject/jaxb/src/main/resources/collectionobjects-common.xsd similarity index 57% rename from services/collectionobject/jaxb/src/main/resources/collectionobject.xsd rename to services/collectionobject/jaxb/src/main/resources/collectionobjects-common.xsd index bb9575e8b..e34e35ce9 100644 --- a/services/collectionobject/jaxb/src/main/resources/collectionobject.xsd +++ b/services/collectionobject/jaxb/src/main/resources/collectionobjects-common.xsd @@ -1,33 +1,34 @@ - - - + + + + - - - - - - - - - + + + + + + + + + - + diff --git a/services/collectionobject/jaxb/src/main/resources/collectionobjects-naturalhistory.xsd b/services/collectionobject/jaxb/src/main/resources/collectionobjects-naturalhistory.xsd new file mode 100644 index 000000000..f066192f0 --- /dev/null +++ b/services/collectionobject/jaxb/src/main/resources/collectionobjects-naturalhistory.xsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + diff --git a/services/collectionobject/service/pom.xml b/services/collectionobject/service/pom.xml index 4be97215e..e4ddeb619 100644 --- a/services/collectionobject/service/pom.xml +++ b/services/collectionobject/service/pom.xml @@ -80,7 +80,7 @@ org.jboss.resteasy resteasy-jaxrs - 1.0.2.GA + 1.1.GA tjws @@ -91,12 +91,12 @@ org.jboss.resteasy resteasy-jaxb-provider - 1.0.2.GA + 1.1.GA org.jboss.resteasy resteasy-multipart-provider - 1.0.2.GA + 1.1.GA diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java index cff244d51..4a9d5930e 100644 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java @@ -1,3 +1,26 @@ +/** + * 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.collectionobject; import javax.ws.rs.Consumes; @@ -13,53 +36,53 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; -import org.collectionspace.services.collectionobject.CollectionObjectList.*; -import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectConstants; import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectHandlerFactory; -import org.collectionspace.services.common.NuxeoClientType; -import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.AbstractCollectionSpaceResource; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.common.repository.DocumentHandler; -import org.collectionspace.services.common.repository.RepositoryClient; -import org.collectionspace.services.common.repository.RepositoryClientFactory; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.util.HttpResponseCodes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path("/collectionobjects") -@Consumes("application/xml") -@Produces("application/xml") -public class CollectionObjectResource { +@Consumes("multipart/mixed") +@Produces("multipart/mixed") +public class CollectionObjectResource + extends AbstractCollectionSpaceResource { - public final static String CO_SERVICE_NAME = "collectionobjects"; + final private String serviceName = "collectionobjects"; final Logger logger = LoggerFactory.getLogger(CollectionObjectResource.class); - //FIXME retrieve client type from configuration - final static NuxeoClientType CLIENT_TYPE = ServiceMain.getInstance().getNuxeoClientType(); - public CollectionObjectResource() { - // do nothing + @Override + public String getServiceName() { + return serviceName; } - @POST - public Response createCollectionObject( - CollectionObject collectionObject) { + @Override + public DocumentHandler createDocumentHandler(ServiceContext ctx) throws Exception { + DocumentHandler docHandler = CollectionObjectHandlerFactory.getInstance().getHandler( + ctx.getRepositoryClientType().toString()); + docHandler.setServiceContext(ctx); + if(ctx.getInput() != null){ + Object obj = ctx.getInputPart(ctx.getCommonPartLabel(), CollectionobjectsCommon.class); + if(obj != null){ + docHandler.setCommonPart((CollectionobjectsCommon) obj); + } + } + return docHandler; + } - String csid = null; + @POST + public Response createCollectionObject(MultipartInput input) { try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - handler.setCommonObject(collectionObject); - csid = client.create(CO_SERVICE_NAME, handler); - collectionObject.setCsid(csid); - if(logger.isDebugEnabled()){ - verbose("createCollectionObject: ", collectionObject); - } + ServiceContext ctx = createServiceContext(input); + DocumentHandler handler = createDocumentHandler(ctx); + String csid = getRepositoryClient(ctx).create(ctx, handler); UriBuilder path = UriBuilder.fromResource(CollectionObjectResource.class); path.path("" + csid); Response response = Response.created(path.build()).build(); @@ -76,10 +99,10 @@ public class CollectionObjectResource { @GET @Path("{csid}") - public CollectionObject getCollectionObject( + public MultipartOutput getCollectionObject( @PathParam("csid") String csid) { if(logger.isDebugEnabled()){ - verbose("getCollectionObject with csid=" + csid); + logger.debug("getCollectionObject with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("getCollectionObject: missing csid!"); @@ -88,14 +111,12 @@ public class CollectionObjectResource { "text/plain").build(); throw new WebApplicationException(response); } - CollectionObject collectionObject = null; + MultipartOutput result = null; try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - client.get(csid, handler); - collectionObject = (CollectionObject) handler.getCommonObject(); + ServiceContext ctx = createServiceContext(null); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).get(ctx, csid, handler); + result = ctx.getOutput(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ logger.debug("getCollectionObject", dnfe); @@ -113,28 +134,24 @@ public class CollectionObjectResource { throw new WebApplicationException(response); } - if(collectionObject == null){ + if(result == null){ Response response = Response.status(Response.Status.NOT_FOUND).entity( "Get failed, the requested CollectionObject CSID:" + csid + ": was not found.").type( "text/plain").build(); throw new WebApplicationException(response); } - if(logger.isDebugEnabled()){ - verbose("getCollectionObject: ", collectionObject); - } - return collectionObject; + return result; } @GET - public CollectionObjectList getCollectionObjectList(@Context UriInfo ui) { - CollectionObjectList collectionObjectList = new CollectionObjectList(); + @Produces("application/xml") + public CollectionobjectsCommonList getCollectionObjectList(@Context UriInfo ui) { + CollectionobjectsCommonList collectionObjectList = new CollectionobjectsCommonList(); try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - client.getAll(CO_SERVICE_NAME, handler); - collectionObjectList = (CollectionObjectList) handler.getCommonObjectList(); + ServiceContext ctx = createServiceContext(null); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).getAll(ctx, handler); + collectionObjectList = (CollectionobjectsCommonList) handler.getCommonPartList(); }catch(Exception e){ if(logger.isDebugEnabled()){ logger.debug("Caught exception in getCollectionObjectList", e); @@ -148,11 +165,11 @@ public class CollectionObjectResource { @PUT @Path("{csid}") - public CollectionObject updateCollectionObject( + public MultipartOutput updateCollectionObject( @PathParam("csid") String csid, - CollectionObject theUpdate) { + MultipartInput theUpdate) { if(logger.isDebugEnabled()){ - verbose("updateCollectionObject with csid=" + csid); + logger.debug("updateCollectionObject with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("updateCollectionObject: missing csid!"); @@ -161,16 +178,12 @@ public class CollectionObjectResource { "text/plain").build(); throw new WebApplicationException(response); } - if(logger.isDebugEnabled()){ - verbose("updateCollectionObject with input: ", theUpdate); - } + MultipartOutput result = null; try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - handler.setCommonObject(theUpdate); - client.update(csid, handler); + ServiceContext ctx = createServiceContext(theUpdate); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).update(ctx, csid, handler); + result = ctx.getOutput(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ logger.debug("caugth exception in updateCollectionObject", dnfe); @@ -184,7 +197,7 @@ public class CollectionObjectResource { Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build(); throw new WebApplicationException(response); } - return theUpdate; + return result; } @DELETE @@ -192,7 +205,7 @@ public class CollectionObjectResource { public Response deleteCollectionObject(@PathParam("csid") String csid) { if(logger.isDebugEnabled()){ - verbose("deleteCollectionObject with csid=" + csid); + logger.debug("deleteCollectionObject with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("deleteCollectionObject: missing csid!"); @@ -202,9 +215,8 @@ public class CollectionObjectResource { throw new WebApplicationException(response); } try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - client.delete(csid); + ServiceContext ctx = createServiceContext(null); + getRepositoryClient(ctx).delete(ctx, csid); return Response.status(HttpResponseCodes.SC_OK).build(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ @@ -221,23 +233,4 @@ public class CollectionObjectResource { } } - - private void verbose(String msg, CollectionObject collectionObject) { - try{ - verbose(msg); - JAXBContext jc = JAXBContext.newInstance( - CollectionObject.class); - - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - m.marshal(collectionObject, System.out); - }catch(Exception e){ - e.printStackTrace(); - } - - } - - private void verbose(String msg) { - System.out.println("CollectionObjectResource. " + msg); - } } diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java deleted file mode 100644 index a08b6289d..000000000 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * - */ -package org.collectionspace.services.collectionobject; - -import java.io.IOException; -import org.dom4j.Document; -import org.dom4j.DocumentException; - -import org.collectionspace.services.collectionobject.CollectionObject; - -/** - * @author remillet - * - */ -public interface CollectionObjectService { - - public final static String CO_SCHEMA_NAME = "collectionobject"; - - // Create - Document postCollectionObject(CollectionObject co) - throws DocumentException, IOException; - - // Read single object - Document getCollectionObject(String csid) throws DocumentException, - IOException; - - // Read a list of objects - Document getCollectionObjectList() throws DocumentException, IOException; - - // Update - Document putCollectionObject(String csid, CollectionObject theUpdate) - throws DocumentException, IOException; - - // Delete - Document deleteCollectionObject(String csid) throws DocumentException, - IOException; -} diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java index 4e593f19d..800f6d5b2 100644 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java @@ -26,11 +26,10 @@ package org.collectionspace.services.collectionobject.nuxeo; import java.util.Iterator; import java.util.List; -import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectConstants; import org.collectionspace.services.CollectionObjectJAXBSchema; -import org.collectionspace.services.collectionobject.CollectionObject; -import org.collectionspace.services.collectionobject.CollectionObjectList; -import org.collectionspace.services.collectionobject.CollectionObjectList.CollectionObjectListItem; +import org.collectionspace.services.collectionobject.CollectionobjectsCommon; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList.CollectionObjectListItem; import org.collectionspace.services.common.repository.DocumentWrapper; import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler; import org.nuxeo.ecm.core.api.DocumentModel; @@ -45,146 +44,69 @@ import org.slf4j.LoggerFactory; * $LastChangedDate: $ */ public class CollectionObjectDocumentModelHandler - extends DocumentModelHandler { + extends DocumentModelHandler { private final Logger logger = LoggerFactory.getLogger(CollectionObjectDocumentModelHandler.class); /** * collectionObject is used to stash JAXB object to use when handle is called * for Action.CREATE, Action.UPDATE or Action.GET */ - private CollectionObject collectionObject; + private CollectionobjectsCommon collectionObject; /** * collectionObjectList is stashed when handle is called * for ACTION.GET_ALL */ - private CollectionObjectList collectionObjectList; - - @Override - public void prepare(Action action) throws Exception { - //no specific action needed - } - + private CollectionobjectsCommonList collectionObjectList; /** - * getCommonObject get associated CollectionObject + * getCommonPart get associated CollectionobjectsCommon * @return */ @Override - public CollectionObject getCommonObject() { + public CollectionobjectsCommon getCommonPart() { return collectionObject; } /** - * setCommonObject set associated collectionobject + * setCommonPart set associated collectionobject * @param collectionObject */ @Override - public void setCommonObject(CollectionObject collectionObject) { + public void setCommonPart(CollectionobjectsCommon collectionObject) { this.collectionObject = collectionObject; } /** - * getCollectionObjectList get associated CollectionObject (for index/GET_ALL) + * getCollectionobjectsCommonList get associated CollectionobjectsCommon (for index/GET_ALL) * @return */ @Override - public CollectionObjectList getCommonObjectList() { + public CollectionobjectsCommonList getCommonPartList() { return collectionObjectList; } @Override - public void setCommonObjectList(CollectionObjectList collectionObjectList) { + public void setCommonPartList(CollectionobjectsCommonList collectionObjectList) { this.collectionObjectList = collectionObjectList; } @Override - public CollectionObject extractCommonObject(DocumentWrapper wrapDoc) + public CollectionobjectsCommon extractCommonPart(DocumentWrapper wrapDoc) throws Exception { - DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); - CollectionObject co = new CollectionObject(); - - //FIXME property get should be dynamically set using schema inspection - //so it does not require hard coding - - // CollectionObject core values - co.setObjectNumber((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.OBJECT_NUMBER))); - co.setOtherNumber((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.OTHER_NUMBER))); - co.setBriefDescription((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.BRIEF_DESCRIPTION))); - co.setComments((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.COMMENTS))); - co.setDistFeatures((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.DIST_FEATURES))); - co.setObjectName((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.OBJECT_NAME))); - co.setResponsibleDept((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.RESPONSIBLE_DEPT))); - co.setTitle((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.TITLE))); - - return co; + throw new UnsupportedOperationException(); } @Override - public void fillCommonObject(CollectionObject co, DocumentWrapper wrapDoc) throws Exception { - DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); - //FIXME property setter should be dynamically set using schema inspection - //so it does not require hard coding - - // a default title for the Dublin Core schema - docModel.setPropertyValue("dublincore:title", CollectionObjectConstants.NUXEO_DC_TITLE); - - // CollectionObject core values - if(co.getObjectNumber() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.OBJECT_NUMBER), - co.getObjectNumber()); - } - if(co.getOtherNumber() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.OTHER_NUMBER), - co.getOtherNumber()); - } - if(co.getBriefDescription() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.BRIEF_DESCRIPTION), - co.getBriefDescription()); - } - if(co.getComments() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.COMMENTS), - co.getComments()); - } - if(co.getDistFeatures() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.DIST_FEATURES), - co.getDistFeatures()); - } - if(co.getObjectName() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.OBJECT_NAME), - co.getObjectName()); - } - if(co.getResponsibleDept() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.RESPONSIBLE_DEPT), - co.getResponsibleDept()); - } - if(co.getTitle() != null){ - docModel.setPropertyValue( - getQProperty(CollectionObjectJAXBSchema.TITLE), - co.getTitle()); - } + public void fillCommonPart(CollectionobjectsCommon co, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException(); } @Override - public CollectionObjectList extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception { + public CollectionobjectsCommonList extractCommonPartList(DocumentWrapper wrapDoc) throws Exception { DocumentModelList docList = (DocumentModelList) wrapDoc.getWrappedObject(); - CollectionObjectList coList = new CollectionObjectList(); - List list = coList.getCollectionObjectListItem(); + CollectionobjectsCommonList coList = new CollectionobjectsCommonList(); + List list = coList.getCollectionObjectListItem(); //FIXME: iterating over a long list of documents is not a long term //strategy...need to change to more efficient iterating in future @@ -192,10 +114,9 @@ public class CollectionObjectDocumentModelHandler while(iter.hasNext()){ DocumentModel docModel = iter.next(); CollectionObjectListItem coListItem = new CollectionObjectListItem(); - coListItem.setObjectNumber((String) docModel.getPropertyValue( - getQProperty(CollectionObjectJAXBSchema.OBJECT_NUMBER))); - //need fully qualified context for URI - coListItem.setUri("/collectionobjects/" + docModel.getId()); + coListItem.setObjectNumber((String) docModel.getProperty(getServiceContext().getCommonPartLabel(), + CollectionObjectJAXBSchema.OBJECT_NUMBER)); + coListItem.setUri(getServiceContextPath() + docModel.getId()); coListItem.setCsid(docModel.getId()); list.add(coListItem); } @@ -204,20 +125,26 @@ public class CollectionObjectDocumentModelHandler } @Override - public void fillCommonObjectList(CollectionObjectList obj, DocumentWrapper wrapDoc) throws Exception { - throw new UnsupportedOperationException(); + public void fillAllParts(DocumentWrapper wrapDoc) throws Exception { + + super.fillAllParts(wrapDoc); + fillDublinCoreObject(wrapDoc); //dublincore might not be needed in future } - + + private void fillDublinCoreObject(DocumentWrapper wrapDoc) throws Exception { + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + //FIXME property setter should be dynamically set using schema inspection + //so it does not require hard coding + // a default title for the Dublin Core schema + docModel.setPropertyValue("dublincore:title", CollectionObjectConstants.NUXEO_DC_TITLE); + } + public String getDocumentType() { - return CollectionObjectConstants.NUXEO_DOCTYPE; + return CollectionObjectConstants.NUXEO_DOCTYPE; } - /** - * getQProperty converts the given property to qualified schema property - * @param prop - * @return - */ - private String getQProperty(String prop) { + @Override + public String getQProperty(String prop) { return CollectionObjectConstants.NUXEO_SCHEMA_NAME + ":" + prop; } } diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java index bcaa606b1..da019e737 100644 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java @@ -23,7 +23,7 @@ */ package org.collectionspace.services.collectionobject.nuxeo; -import org.collectionspace.services.common.NuxeoClientType; +import org.collectionspace.services.common.ClientType; import org.collectionspace.services.common.repository.DocumentHandler; /** @@ -45,9 +45,9 @@ public class CollectionObjectHandlerFactory { } public DocumentHandler getHandler(String clientType) { - if(NuxeoClientType.JAVA.toString().equals(clientType)){ + if(ClientType.JAVA.toString().equals(clientType)){ return new CollectionObjectDocumentModelHandler(); - } else if(NuxeoClientType.REST.toString().equals(clientType)) { + } else if(ClientType.REST.toString().equals(clientType)) { return new CollectionObjectRepresenationHandler(); } throw new IllegalArgumentException("Not supported client=" + clientType); diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java index 44dd741a3..034b0875b 100644 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java @@ -27,13 +27,13 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.StringTokenizer; import org.collectionspace.services.CollectionObjectJAXBSchema; -import org.collectionspace.services.collectionobject.CollectionObject; -import org.collectionspace.services.collectionobject.CollectionObjectList; -import org.collectionspace.services.collectionobject.CollectionObjectList.CollectionObjectListItem; +import org.collectionspace.services.collectionobject.CollectionobjectsCommon; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList.CollectionObjectListItem; import org.collectionspace.services.common.repository.DocumentWrapper; import org.collectionspace.services.nuxeo.client.rest.RepresentationHandler; -import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectConstants; import org.dom4j.Document; import org.dom4j.Element; @@ -47,7 +47,7 @@ import org.slf4j.LoggerFactory; * $LastChangedDate: $ */ public class CollectionObjectRepresenationHandler - extends RepresentationHandler + extends RepresentationHandler { private final Logger logger = LoggerFactory.getLogger(CollectionObjectRepresenationHandler.class); @@ -55,12 +55,12 @@ public class CollectionObjectRepresenationHandler * collectionObject is used to stash JAXB object to use when handle is called * for Action.CREATE, Action.UPDATE or Action.GET */ - private CollectionObject collectionObject; + private CollectionobjectsCommon collectionObject; /** * collectionObjectList is stashed when handle is called * for ACTION.GET_ALL */ - private CollectionObjectList collectionObjectList; + private CollectionobjectsCommonList collectionObjectList; @Override public void prepare(Action action) throws Exception { @@ -73,7 +73,7 @@ public class CollectionObjectRepresenationHandler private void prepare() { Map queryParams = getQueryParams(); - CollectionObject co = getCommonObject(); + CollectionobjectsCommon co = getCommonPart(); // todo: intelligent merge needed if(co.getObjectNumber() != null){ queryParams.put(CollectionObjectConstants.NUXEO_SCHEMA_NAME + @@ -117,10 +117,10 @@ public class CollectionObjectRepresenationHandler } @Override - public CollectionObject extractCommonObject(DocumentWrapper wrapDoc) + public CollectionobjectsCommon extractCommonPart(DocumentWrapper wrapDoc) throws Exception { Document document = (Document) wrapDoc.getWrappedObject(); - CollectionObject co = new CollectionObject(); + CollectionobjectsCommon co = new CollectionobjectsCommon(); //FIXME property get should be dynamically set using schema inspection //so it does not require hard coding @@ -177,20 +177,20 @@ public class CollectionObjectRepresenationHandler } @Override - public void fillCommonObject(CollectionObject co, DocumentWrapper wrapDoc) + public void fillCommonPart(CollectionobjectsCommon co, DocumentWrapper wrapDoc) throws Exception { //Nuxeo REST takes create/update through queryParams, nothing to do here } @Override - public CollectionObjectList extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception { + public CollectionobjectsCommonList extractCommonPartList(DocumentWrapper wrapDoc) throws Exception { Document document = (Document) wrapDoc.getWrappedObject(); // debug if(logger.isDebugEnabled()){ logger.debug(document.asXML()); } - CollectionObjectList coList = new CollectionObjectList(); - List list = coList.getCollectionObjectListItem(); + CollectionobjectsCommonList coList = new CollectionobjectsCommonList(); + List list = coList.getCollectionObjectListItem(); Element root = document.getRootElement(); for(Iterator i = root.elementIterator(); i.hasNext();){ @@ -210,29 +210,24 @@ public class CollectionObjectRepresenationHandler return coList; } - @Override - public void fillCommonObjectList(CollectionObjectList obj, DocumentWrapper wrapDoc) - throws Exception { - throw new UnsupportedOperationException(); - } @Override - public CollectionObject getCommonObject() { + public CollectionobjectsCommon getCommonPart() { return collectionObject; } @Override - public void setCommonObject(CollectionObject obj) { + public void setCommonPart(CollectionobjectsCommon obj) { this.collectionObject = obj; } @Override - public CollectionObjectList getCommonObjectList() { + public CollectionobjectsCommonList getCommonPartList() { return collectionObjectList; } @Override - public void setCommonObjectList(CollectionObjectList obj) { + public void setCommonPartList(CollectionobjectsCommonList obj) { this.collectionObjectList = obj; } @@ -240,13 +235,11 @@ public class CollectionObjectRepresenationHandler return CollectionObjectConstants.NUXEO_DOCTYPE; } - /** - * getQProperty converts the given property to qualified schema property - * @param prop - * @return - */ - private String getQProperty(String prop) { + + @Override + public String getQProperty(String prop) { return CollectionObjectConstants.NUXEO_SCHEMA_NAME + ":" + prop; } + } diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java deleted file mode 100644 index e19e56d3a..000000000 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java +++ /dev/null @@ -1,224 +0,0 @@ -/** - * - */ -package org.collectionspace.services.collectionobject.nuxeo; - -import org.collectionspace.services.collectionobject.CollectionObjectService; -import org.collectionspace.services.*; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.collectionspace.services.nuxeo.client.rest.NuxeoRESTClient; -import org.collectionspace.services.nuxeo.CollectionSpaceServiceNuxeoImpl; -import org.collectionspace.services.collectionobject.CollectionObject; -import org.collectionspace.services.CollectionObjectJAXBSchema; -import org.collectionspace.services.nuxeo.util.NuxeoUtils; - -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.io.SAXReader; -import org.restlet.resource.Representation; - -import org.nuxeo.ecm.core.api.IdRef; -import org.nuxeo.ecm.core.api.repository.RepositoryInstance; -import org.nuxeo.ecm.core.api.DocumentModel; -import org.nuxeo.ecm.core.api.DocumentRef; - - - -/** - * @author remillet - * - */ -public class CollectionObjectServiceNuxeoImpl extends - CollectionSpaceServiceNuxeoImpl implements CollectionObjectService { - - final static String CO_NUXEO_DOCTYPE = "CollectionObject"; - final static String CO_NUXEO_SCHEMA_NAME = "collectionobject"; - final static String CO_NUXEO_DC_TITLE = "CollectionSpace-CollectionObject"; - - // replace WORKSPACE_UID for resource workspace - static String CS_COLLECTIONOBJECT_WORKSPACE_UID = "9dd20955-fce7-4a87-8319-040ab9543f4f"; - - public Document deleteCollectionObject(String csid) - throws DocumentException, IOException { - - Document result = null; - -// NuxeoRESTClient nxClient = getClient(); -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// -// pathParams.add("default"); -// pathParams.add(csid); -// pathParams.add("deleteDocumentRestlet"); -// Representation res = nxClient.get(pathParams, queryParams); -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - public Document getCollectionObject(String csid) throws DocumentException, - IOException { - - // Calling via Nuxeo Java API - //getCollectionObjectViaJavaAPI(csid); - - // Return to normal Nuxeo REST call - Document result = null; -// -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// -// pathParams.add("default"); -// pathParams.add(csid); -// pathParams.add("export"); -// queryParams.put("format", "XML"); -// -// NuxeoRESTClient nxClient = getClient(); -// Representation res = nxClient.get(pathParams, queryParams); -// -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - - public Document getCollectionObjectList() throws DocumentException, - IOException { - Document result = null; - -// NuxeoRESTClient nxClient = getClient(); -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// pathParams = Arrays.asList("default", -// CS_COLLECTIONOBJECT_WORKSPACE_UID, "browse"); -// Representation res = nxClient.get(pathParams, queryParams); -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - public Document postCollectionObject(CollectionObject co) - throws DocumentException, IOException { - Document result = null; - -// NuxeoRESTClient nxClient = getClient(); -// -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// pathParams.add("default"); -// pathParams.add(CS_COLLECTIONOBJECT_WORKSPACE_UID); -// pathParams.add("createDocument"); -// queryParams.put("docType", CO_NUXEO_DOCTYPE); -// -// // a default title for the Dublin Core schema -// queryParams.put("dublincore:title", CO_NUXEO_DC_TITLE); -// -// // CollectionObject core values -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.OBJECT_NUMBER, co -// .getObjectNumber()); -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.OTHER_NUMBER, co.getOtherNumber()); -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.BRIEF_DESCRIPTION, co -// .getBriefDescription()); -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.COMMENTS, co.getComments()); -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.DIST_FEATURES, co -// .getDistFeatures()); -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.OBJECT_NAME, co.getObjectName()); -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.RESPONSIBLE_DEPT, co -// .getResponsibleDept()); -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.TITLE, co.getTitle()); -// -// ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]); -// Representation res = nxClient.post(pathParams, queryParams, bais); -// -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - public Document putCollectionObject(String csid, CollectionObject theUpdate) - throws DocumentException, IOException { - - Document result = null; - -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// pathParams.add("default"); -// pathParams.add(csid); -// pathParams.add("updateDocumentRestlet"); -// -// // todo: intelligent merge needed -// if (theUpdate.getObjectNumber() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.OBJECT_NUMBER, theUpdate -// .getObjectNumber()); -// } -// -// if (theUpdate.getOtherNumber() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.OTHER_NUMBER, theUpdate -// .getOtherNumber()); -// } -// -// if (theUpdate.getBriefDescription() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.BRIEF_DESCRIPTION, theUpdate -// .getBriefDescription()); -// } -// -// if (theUpdate.getComments() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.COMMENTS, theUpdate -// .getComments()); -// } -// -// if (theUpdate.getDistFeatures() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.DIST_FEATURES, theUpdate -// .getDistFeatures()); -// } -// -// if (theUpdate.getObjectName() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.OBJECT_NAME, theUpdate -// .getObjectName()); -// } -// -// if (theUpdate.getResponsibleDept() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.RESPONSIBLE_DEPT, theUpdate -// .getResponsibleDept()); -// } -// -// if (theUpdate.getTitle() != null) { -// queryParams.put(CO_NUXEO_SCHEMA_NAME + ":" -// + CollectionObjectJAXBSchema.TITLE, theUpdate.getTitle()); -// } -// -// NuxeoRESTClient nxClient = getClient(); -// Representation res = nxClient.get(pathParams, queryParams); -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - -} diff --git a/services/common/build.xml b/services/common/build.xml index a3fffc528..13a59be0f 100644 --- a/services/common/build.xml +++ b/services/common/build.xml @@ -109,19 +109,20 @@ - + + + - + - + diff --git a/services/common/pom.xml b/services/common/pom.xml index 16906e47e..c54f50d20 100644 --- a/services/common/pom.xml +++ b/services/common/pom.xml @@ -13,10 +13,21 @@ services.common + + com.sun.xml.bind + jaxb-impl + + + org.jvnet.jaxb2-commons + property-listener-injector + + + org.jvnet.jaxb2_commons + runtime + org.jboss.resteasy resteasy-jaxrs - 1.0.2.GA tjws @@ -27,12 +38,12 @@ org.jboss.resteasy resteasy-jaxb-provider - 1.0.2.GA + 1.1.GA org.jboss.resteasy resteasy-multipart-provider - 1.0.2.GA + 1.1.GA @@ -52,7 +63,13 @@ - + + javax.servlet + servlet-api + 2.5 + provided + + javax.security jaas @@ -152,21 +169,7 @@ 1.1.1 - - com.sun.xml.bind - jaxb-impl - 2.0.2 - - - org.jvnet.jaxb2-commons - property-listener-injector - 1.0 - - - org.jvnet.jaxb2_commons - runtime - 0.4.1.4 - + @@ -182,19 +185,7 @@ - - - - javax.activation - activation - 1.1 - - - com.sun.xml.bind - jaxb-impl - 2.1.2 - - + -XtoString diff --git a/services/common/profiles.xml b/services/common/profiles.xml new file mode 100644 index 000000000..347b9df22 --- /dev/null +++ b/services/common/profiles.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/services/common/src/main/config/service-config.xml b/services/common/src/main/config/service-config.xml index 01bc94a1f..a6315b983 100644 --- a/services/common/src/main/config/service-config.xml +++ b/services/common/src/main/config/service-config.xml @@ -12,22 +12,25 @@ - + + + 127.0.0.1 62474 - java Administrator Administrator - - - + java + org.collectionspace.services.nuxeo.client.java.RepositoryJavaClient + + + + + - - + collectionobjects CollectionObjects @@ -37,17 +40,15 @@ intakes Intakes - - relations Relations - + acquisitions Acquisitions - - + + diff --git a/services/common/src/main/config/tenant-bindings.xml b/services/common/src/main/config/tenant-bindings.xml new file mode 100644 index 000000000..ddcec896d --- /dev/null +++ b/services/common/src/main/config/tenant-bindings.xml @@ -0,0 +1,112 @@ + + + + + + + + nuxeo-java + + + + + + + + + + + + + + + + + + + + + + + + + nuxeo-java + + + + + + + + + + + + + + + + + + + nuxeo-java + + + + + + + + + + + + + + + + + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java b/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java new file mode 100644 index 000000000..ad2fef0dc --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java @@ -0,0 +1,70 @@ +/** + * 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.common; + +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.context.ServiceContextImpl; +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.RepositoryClient; +import org.collectionspace.services.common.repository.RepositoryClientFactory; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; + +public abstract class AbstractCollectionSpaceResource + implements CollectionSpaceResource { + + // Fields for default client factory and client + private RepositoryClientFactory repositoryClientFactory; + private RepositoryClient repositoryClient; + + public AbstractCollectionSpaceResource() { + repositoryClientFactory = RepositoryClientFactory.getInstance(); + } + + @Override + abstract public String getServiceName(); + + @Override + public RepositoryClientFactory getRepositoryClientFactory() { + return repositoryClientFactory; + } + + @Override + synchronized public RepositoryClient getRepositoryClient(ServiceContext ctx) { + if(repositoryClient != null){ + return repositoryClient; + } + repositoryClient = repositoryClientFactory.getClient(ctx.getRepositoryClientName()); + return repositoryClient; + } + + @Override + public ServiceContext createServiceContext(MultipartInput input) throws Exception { + ServiceContext ctx = new ServiceContextImpl(getServiceName()); + ctx.setInput(input); + return ctx; + } + + @Override + abstract public DocumentHandler createDocumentHandler(ServiceContext ctx) throws Exception ; +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceHandlerFactory.java b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceHandlerFactory.java index cd3368e26..b3e310b0e 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceHandlerFactory.java +++ b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceHandlerFactory.java @@ -1,8 +1,37 @@ +/** + * 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.common; import org.collectionspace.services.common.repository.DocumentHandler; -import org.collectionspace.services.common.NuxeoClientType; public interface CollectionSpaceHandlerFactory { + /** + * getHandler gets or creates a document handler per given client type + * @param clientType (java|rest) + * @return + * @throws IllegalArgumentException + */ public DocumentHandler getHandler(String clientType) throws IllegalArgumentException; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java index e4b33b757..2f601c334 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java +++ b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java @@ -1,38 +1,73 @@ -package org.collectionspace.services.common; - -import org.collectionspace.services.common.repository.DocumentHandler; -import org.collectionspace.services.common.repository.RepositoryClient; -import org.collectionspace.services.common.repository.RepositoryClientFactory; -import org.collectionspace.services.common.CollectionSpaceHandlerFactory; -//import org.collectionspace.services.relation.nuxeo.RelationHandlerFactory; - -public abstract class CollectionSpaceResource { - - // Fields for default client factory and client - private RepositoryClientFactory defaultClientFactory; - private RepositoryClient defaultClient; - - // Fields for default document handler factory and handler - private CollectionSpaceHandlerFactory defaultHandlerFactory; - private DocumentHandler defaultHandler; - - // Methods that subclasses must implement - abstract protected String getClientType(); - abstract protected RepositoryClientFactory getDefaultClientFactory(); - abstract protected CollectionSpaceHandlerFactory getDefaultHandlerFactory(); - - protected RepositoryClient getDefaultClient() { - return this.defaultClient; - } - - protected DocumentHandler getDefaultHandler() { - return this.defaultHandler; - } - - public CollectionSpaceResource() { - defaultClientFactory = getDefaultClientFactory(); //implemented by subclasses - defaultClient = defaultClientFactory.getClient(getClientType()); - defaultHandlerFactory = getDefaultHandlerFactory(); //implemented by subclasses - defaultHandler = defaultHandlerFactory.getHandler(getClientType()); - } -} +/** + * 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.common; + +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.RepositoryClient; +import org.collectionspace.services.common.repository.RepositoryClientFactory; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; + +/** + * CollectionSpaceResource is a resource interface implemented by every + * entity/service in CollectionSpace + */ +public interface CollectionSpaceResource { + + /** + * getServiceName returns the name of the service + */ + public String getServiceName(); + + /** + * getRepositoryClientFactory + * @return + */ + public RepositoryClientFactory getRepositoryClientFactory(); + + /** + * getRepositoryClient + * @param ctx service context + */ + public RepositoryClient getRepositoryClient(ServiceContext ctx); + + /** + * createServiceContext is a facotry method to create a service context + * a service contex is created on every service request call + * @param input + * @return + */ + public ServiceContext createServiceContext(MultipartInput input) throws Exception; + + /** + * createDocumentHandler creates a document handler and populates it with given + * service context. document handler should never be used + * across service invocations. it is a stateful object that holds request, + * response and service context + * @param ctx + * @return + */ + public DocumentHandler createDocumentHandler(ServiceContext ctx) throws Exception ; +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/ServiceContextListener.java b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceServiceContextListener.java similarity index 58% rename from services/common/src/main/java/org/collectionspace/services/common/ServiceContextListener.java rename to services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceServiceContextListener.java index 5015d7394..c7e72736f 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/ServiceContextListener.java +++ b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceServiceContextListener.java @@ -8,23 +8,25 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** - * ServiceContextListener is a ServletContextListener that helps initialize + * CollectionSpaceServiceContextListener is a ServletContextListener that helps initialize * the services layer at deployment and undeployment times */ -public class ServiceContextListener implements ServletContextListener { +public class CollectionSpaceServiceContextListener implements ServletContextListener { + @Override public void contextInitialized(ServletContextEvent event) { try{ - ServletContext sc = event.getServletContext(); - ServiceMain svcMain = ServiceMain.getInstance(); //first access initializes as well - svcMain.getWorkspaceIds(); - }catch(Exception e) { + ServletContext sc = event.getServletContext(); + ServiceMain svcMain = ServiceMain.getInstance(); //first access initializes as well + svcMain.retrieveAllWorkspaceIds(); + }catch(Exception e){ e.printStackTrace(); //fail here throw new RuntimeException(e); } } + @Override public void contextDestroyed(ServletContextEvent event) { ServiceMain.getInstance().release(); } 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 75c6efc4e..2d8e39eb2 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 @@ -3,13 +3,9 @@ */ package org.collectionspace.services.common; -import java.io.File; import java.util.Hashtable; -import java.util.List; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Unmarshaller; -import org.collectionspace.services.common.ServiceConfig.NuxeoWorkspace; -import org.collectionspace.services.common.ServiceConfig.NuxeoWorkspace.Workspace; +import org.collectionspace.services.common.config.ServicesConfigReader; +import org.collectionspace.services.common.config.TenantBindingConfigReader; import org.collectionspace.services.nuxeo.client.java.NuxeoConnector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,16 +17,15 @@ import org.slf4j.LoggerFactory; */ public class ServiceMain { + /** + * volatile is used here to assume about ordering (post JDK 1.5) + */ private static volatile ServiceMain instance = null; - final public static String CSPACE_DIR_NAME = "cspace"; - final public static String CONFIG_DIR_NAME = "config" + File.separator + "services"; - final private static String CONFIG_FILE_NAME = "service-config.xml"; final Logger logger = LoggerFactory.getLogger(ServiceMain.class); - private ServiceConfig serviceConfig; - private Hashtable serviceWorkspaces = new Hashtable(); private NuxeoConnector nuxeoConnector; private String serverRootDir = null; - private NuxeoClientType nuxeoClientType = null; + private ServicesConfigReader servicesConfigReader; + private TenantBindingConfigReader tenantBindingConfigReader; private ServiceMain() { } @@ -64,10 +59,11 @@ public class ServiceMain { private void initialize() throws Exception { setServerRootDir(); - serviceConfig = readConfig(); - if(getNuxeoClientType().equals(NuxeoClientType.JAVA)){ + readConfig(); + if(getClientType().equals(ClientType.JAVA)){ nuxeoConnector = NuxeoConnector.getInstance(); - nuxeoConnector.initialize(serviceConfig.getNuxeoClientConfig()); + nuxeoConnector.initialize( + getServicesConfigReader().getConfiguration().getRepositoryClient()); } } @@ -80,7 +76,6 @@ public class ServiceMain { if(nuxeoConnector != null){ nuxeoConnector.release(); } - serviceWorkspaces.clear(); instance = null; }catch(Exception e){ e.printStackTrace(); @@ -88,74 +83,28 @@ public class ServiceMain { } } - private ServiceConfig readConfig() throws Exception { - JAXBContext jc = JAXBContext.newInstance(ServiceConfig.class); - Unmarshaller um = jc.createUnmarshaller(); - String configFileName = getServerRootDir() + - File.separator + CSPACE_DIR_NAME + - File.separator + CONFIG_DIR_NAME + - File.separator + CONFIG_FILE_NAME; - File configFile = new File(configFileName); - if(!configFile.exists()){ - String msg = "Could not find configuration file " + configFileName; - logger.error(msg); - throw new RuntimeException(msg); - } - ServiceConfig sconfig = (ServiceConfig) um.unmarshal(configFile); - if(logger.isDebugEnabled()){ - logger.debug("readConfig() read config file " + configFile.getAbsolutePath()); - } - nuxeoClientType = sconfig.getNuxeoClientConfig().getClientType(); - if(logger.isDebugEnabled()) { - logger.debug("using Nuxeo client=" + nuxeoClientType.toString()); - } - return sconfig; - } - - synchronized public void getWorkspaceIds() throws Exception { - Hashtable workspaceIds = new Hashtable(); + private void readConfig() throws Exception { + //read service config + servicesConfigReader = new ServicesConfigReader(getServerRootDir()); + getServicesConfigReader().read(); - if(getNuxeoClientType().equals(NuxeoClientType.JAVA)){ - workspaceIds = nuxeoConnector.retrieveWorkspaceIds(); - } - NuxeoWorkspace nuxeoWorkspace = serviceConfig.getNuxeoWorkspace(); - List workspaces = nuxeoWorkspace.getWorkspace(); - String workspaceId = null; - for(Workspace workspace : workspaces){ - if(getNuxeoClientType().equals(NuxeoClientType.JAVA)){ - workspaceId = workspaceIds.get(workspace.getWorkspaceName().toLowerCase()); - if(workspaceId == null){ - logger.warn("failed to retrieve workspace id for " + workspace.getWorkspaceName()); - //FIXME: should we throw an exception here? - continue; - } - }else{ - workspaceId = workspace.getWorkspaceId(); - if(workspaceId == null || "".equals(workspaceId)){ - logger.error("could not find workspace id for " + workspace.getWorkspaceName()); - //FIXME: should we throw an exception here? - continue; - } - } + tenantBindingConfigReader = new TenantBindingConfigReader(getServerRootDir()); + getTenantBindingConfigReader().read(); + } - serviceWorkspaces.put(workspace.getServiceName(), workspaceId); - if(logger.isDebugEnabled()){ - logger.debug("retrieved workspace id=" + workspaceId + - " service=" + workspace.getServiceName() + - " workspace=" + workspace.getWorkspaceName()); - } - } + void retrieveAllWorkspaceIds() throws Exception { + //all configs are read, connector is initialized, retrieve workspaceids + getTenantBindingConfigReader().retrieveAllWorkspaceIds(); } /** - * @return the serviceConfig + * retrieveWorkspaceIds for given tenant domain. + * @param tenantDomain + * @return Hashtable key=workspace name, value=workspace id + * @throws Exception */ - public ServiceConfig getServiceConfig() { - return serviceConfig; - } - - synchronized public String getWorkspaceId(String serviceName) { - return serviceWorkspaces.get(serviceName); + public Hashtable retrieveWorkspaceIds(String tenantDomain) throws Exception { + return nuxeoConnector.retrieveWorkspaceIds(tenantDomain); } /** @@ -180,9 +129,30 @@ public class ServiceMain { } /** - * @return the nuxeoClientType + * @return the serviceConfig + */ + public ServiceConfig getServiceConfig() { + return getServicesConfigReader().getConfiguration(); + } + + /** + * @return the clientType + */ + public ClientType getClientType() { + return getServicesConfigReader().getClientType(); + } + + /** + * @return the servicesConfigReader + */ + public ServicesConfigReader getServicesConfigReader() { + return servicesConfigReader; + } + + /** + * @return the tenantBindingConfigReader */ - public NuxeoClientType getNuxeoClientType() { - return nuxeoClientType; + public TenantBindingConfigReader getTenantBindingConfigReader() { + return tenantBindingConfigReader; } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/config/AbstractConfigReader.java b/services/common/src/main/java/org/collectionspace/services/common/config/AbstractConfigReader.java new file mode 100644 index 000000000..8621caa35 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/config/AbstractConfigReader.java @@ -0,0 +1,86 @@ +/** + * 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.common.config; + +import java.io.File; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * AbstractConfigReader + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public abstract class AbstractConfigReader + implements ConfigReader { + + private final Logger logger = LoggerFactory.getLogger(AbstractConfigReader.class); + private String serverRootDir; + + AbstractConfigReader(String serverRootDir) { + this.serverRootDir = serverRootDir; + } + + @Override + abstract public String getFileName(); + + @Override + abstract public void read() throws Exception; + + @Override + abstract public T getConfiguration(); + + + /** + * parse parses given configuration file from the disk based on given class + * definition + * @param configFile + * @param clazz + * @return A JAXB object + * @throws Exception + */ + protected Object parse(File configFile, Class clazz) throws Exception { + JAXBContext jc = JAXBContext.newInstance(clazz); + Unmarshaller um = jc.createUnmarshaller(); + Object readObject = um.unmarshal(configFile); + if(logger.isDebugEnabled()){ + logger.debug("read() read file " + configFile.getAbsolutePath()); + } + return readObject; + } + + protected String getAbsoluteFileName(String configFileName) { + return serverRootDir + + File.separator + CSPACE_DIR_NAME + + File.separator + CONFIG_DIR_NAME + + File.separator + configFileName; + } + + protected String getServerRootDir() { + return serverRootDir; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/config/ConfigReader.java b/services/common/src/main/java/org/collectionspace/services/common/config/ConfigReader.java new file mode 100644 index 000000000..689841cf8 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/config/ConfigReader.java @@ -0,0 +1,54 @@ +/** + * 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.common.config; + +import java.io.File; + +/** + * ConfigReader is an interface for a configuration reader + */ +public interface ConfigReader { + + final public static String CSPACE_DIR_NAME = "cspace"; + final public static String CONFIG_DIR_NAME = "config" + File.separator + "services"; + + /** + * getFileName - get configuration file name + * @return + */ + public String getFileName(); + + /** + * read parse and read the configruation file. + * @throws Exception + */ + public void read() throws Exception; + + /** + * getConfig get configuration binding + * @return + */ + public T getConfiguration(); +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/config/ServicesConfigReader.java b/services/common/src/main/java/org/collectionspace/services/common/config/ServicesConfigReader.java new file mode 100644 index 000000000..9ce98deac --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/config/ServicesConfigReader.java @@ -0,0 +1,94 @@ +/** + * 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.common.config; + +import java.io.File; +import org.collectionspace.services.common.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ServicesConfigReader reads service layer specific configuration + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class ServicesConfigReader + extends AbstractConfigReader { + + final private static String CONFIG_FILE_NAME = "service-config.xml"; + final Logger logger = LoggerFactory.getLogger(ServicesConfigReader.class); + private ServiceConfig serviceConfig; + private ClientType clientType; + private String clientClassName; + + public ServicesConfigReader(String serverRootDir) { + super(serverRootDir); + } + + @Override + public String getFileName() { + return CONFIG_FILE_NAME; + } + + @Override + public void read() throws Exception { + String configFileName = getAbsoluteFileName(CONFIG_FILE_NAME); + File configFile = new File(configFileName); + if(!configFile.exists()){ + String msg = "Could not find configuration file " + configFileName; + logger.error(msg); + throw new RuntimeException(msg); + } + serviceConfig = (ServiceConfig) parse(configFile, ServiceConfig.class); + clientType = serviceConfig.getRepositoryClient().getClientType(); + if(clientType == null){ + String msg = "Missing in "; + logger.error(msg); + throw new IllegalArgumentException(msg); + } + clientClassName = serviceConfig.getRepositoryClient().getClientClass(); + if(clientClassName == null){ + String msg = "Missing in "; + logger.error(msg); + throw new IllegalArgumentException(msg); + } + if(logger.isDebugEnabled()){ + logger.debug("using client=" + clientType.toString() + " class=" + clientClassName); + } + } + + @Override + public ServiceConfig getConfiguration() { + return serviceConfig; + } + + public ClientType getClientType() { + return clientType; + } + + public String getClientClass() { + return clientClassName; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/config/TenantBindingConfigReader.java b/services/common/src/main/java/org/collectionspace/services/common/config/TenantBindingConfigReader.java new file mode 100644 index 000000000..d6186a873 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/config/TenantBindingConfigReader.java @@ -0,0 +1,193 @@ +/** + * 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.common.config; + +import java.io.File; +import java.util.Hashtable; +import java.util.List; +import org.collectionspace.services.common.ClientType; +import org.collectionspace.services.common.RepositoryWorkspaceType; +import org.collectionspace.services.common.ServiceConfig; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.service.ServiceBindingType; +import org.collectionspace.services.common.tenant.TenantBindingType; +import org.collectionspace.services.common.tenant.TenantBindingConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ServicesConfigReader reads service layer specific configuration + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class TenantBindingConfigReader + extends AbstractConfigReader { + + final private static String CONFIG_FILE_NAME = "tenant-bindings.xml"; + final Logger logger = LoggerFactory.getLogger(TenantBindingConfigReader.class); + private TenantBindingConfig tenantBindingConfig; + //tenant name, tenant binding + private Hashtable tenantBindings = + new Hashtable(); + //tenant-qualified servicename, service binding + private Hashtable serviceBindings = + new Hashtable(); + //tenant-qualified service, workspace + private Hashtable serviceWorkspaces = new Hashtable(); + + public TenantBindingConfigReader(String serverRootDir) { + super(serverRootDir); + } + + @Override + public String getFileName() { + return CONFIG_FILE_NAME; + } + + @Override + public void read() throws Exception { + String configFileName = getAbsoluteFileName(CONFIG_FILE_NAME); + File configFile = new File(configFileName); + if(!configFile.exists()){ + String msg = "Could not find configuration file " + configFileName; + logger.error(msg); + throw new RuntimeException(msg); + } + tenantBindingConfig = (TenantBindingConfig) parse(configFile, TenantBindingConfig.class); + for(TenantBindingType tenantBinding : tenantBindingConfig.getTenantBinding()){ + tenantBindings.put(tenantBinding.getId(), tenantBinding); + readServiceBindings(tenantBinding); + if(logger.isDebugEnabled()){ + logger.debug("read() added tenant id=" + tenantBinding.getId() + + " name=" + tenantBinding.getName()); + } + } + } + + private void readServiceBindings(TenantBindingType tenantBinding) throws Exception { + for(ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()){ + String key = getTenantQualifiedServiceName(tenantBinding.getId(), + serviceBinding.getName()); + serviceBindings.put(key, serviceBinding); + if(logger.isDebugEnabled()){ + logger.debug("readServiceBindings() added service " + + " name=" + key + + " workspace=" + serviceBinding.getName()); + } + } + } + + /** + * retrieveWorkspaceIds is called at initialization time to retrieve + * workspace ids of all the tenants + * @throws Exception + */ + public void retrieveAllWorkspaceIds() throws Exception { + for(TenantBindingType tenantBinding : tenantBindings.values()){ + retrieveWorkspaceIds(tenantBinding); + } + } + + public void retrieveWorkspaceIds(TenantBindingType tenantBinding) throws Exception { + String tenantDomain = tenantBinding.getRepositoryDomain(); + Hashtable workspaceIds = new Hashtable(); + ServiceMain svcMain = ServiceMain.getInstance(); + ClientType clientType = svcMain.getClientType(); + if(clientType.equals(ClientType.JAVA)){ + workspaceIds = svcMain.retrieveWorkspaceIds(tenantDomain); + } + for(ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()){ + String serviceName = serviceBinding.getName(); + String workspaceId = null; + //workspace name is service name by convention + String workspace = serviceBinding.getName().toLowerCase(); + if(clientType.equals(ClientType.JAVA)){ + workspaceId = workspaceIds.get(workspace); + if(workspaceId == null){ + logger.warn("failed to retrieve workspace id for " + workspace); + //FIXME: should we throw an exception here? + continue; + } + }else{ + workspaceId = serviceBinding.getRepositoryWorkspaceId(); + if(workspaceId == null || "".equals(workspaceId)){ + logger.error("could not find workspace id for " + workspace); + //FIXME: should we throw an exception here? + continue; + } + } + String tenantService = getTenantQualifiedServiceName(tenantBinding.getId(), serviceName); + serviceWorkspaces.put(tenantService, workspaceId); + if(logger.isDebugEnabled()){ + logger.debug("retrieved workspace id=" + workspaceId + + " service=" + serviceName + + " workspace=" + workspace); + } + } + } + + @Override + public TenantBindingConfig getConfiguration() { + return tenantBindingConfig; + } + + /** + * getTenantBinding gets tenant binding for given tenant + * @param tenantId + * @return + */ + public TenantBindingType getTenantBinding( + String tenantId) { + return tenantBindings.get(tenantId); + } + + /** + * getServiceBinding gets service binding for given tenant for a given service + * @param tenantId + * @param serviceName + * @return + */ + public ServiceBindingType getServiceBinding( + String tenantId, String serviceName) { + String key = getTenantQualifiedServiceName(tenantId, serviceName); + return serviceBindings.get(key); + } + + /** + * getWorkspaceId retrieves workspace id for given tenant for given service + * @param tenantId + * @param serviceName + * @return + */ + public String getWorkspaceId(String tenantId, String serviceName) { + String tenantService = getTenantQualifiedServiceName(tenantId, serviceName); + return serviceWorkspaces.get(tenantService); + } + + public static String getTenantQualifiedServiceName( + String tenantId, String serviceName) { + return tenantId + "." + serviceName.toLowerCase(); + } +} 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 new file mode 100644 index 000000000..a74d5561d --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java @@ -0,0 +1,161 @@ +/** + * 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.common.context; + +import java.io.IOException; +import java.util.Map; +import org.collectionspace.services.common.ClientType; +import org.collectionspace.services.common.service.ObjectPartType; +import org.collectionspace.services.common.service.ServiceBindingType; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; +import org.w3c.dom.Document; + +/** + * + * ServiceContext is used to pass along metadata and runtime context + * between various components of the service framework while processing + * a service request. + */ +public interface ServiceContext { + + /** + * getTenantId get tenant id + * @return tenant id + */ + public String getTenantId(); + + /** + * getTenantName get tenant name from the binding + * @return tenant name such as movingimage.us + */ + public String getTenantName(); + + /** + * getServiceBinding gets service binding metadata + * @return service binding metadata + */ + public ServiceBindingType getServiceBinding(); + + /** + * getServiceName returns the unqualified name of the service + * @return service name + */ + public String getServiceName(); + + /** + * getQualifiedServiceName returns tenant id qualified service name + * @return tenant qualified service name + */ + public String getQualifiedServiceName(); + + /** + * getRepositoryDomainName returns repository domain for the tenant + * @return repository domain for the tenant + */ + public String getRepositoryDomainName(); + + /** + * getRepositoryClientName returns the repository client name as + * configured for the service + */ + public String getRepositoryClientName(); + + /** + * getRepositoryClientType returns the type of client configured for the + * service layer + * @param ctx service context + * @return + */ + public ClientType getRepositoryClientType(); + + /** + * getRepositoryWorkspaceName returns repository workspace for the service for + * the tenant. Not every service has a corresponding repository workspace. + * If the service does not have any repository workspace, this method + * returns null. + * @return repository workspace + */ + public String getRepositoryWorkspaceName(); + + /** + * getRepositoryWorksapceId returns workspace id for the service for the + * tenant. Not every service has a corresponding repository workspace. + * If the service does not have any repository workspace, this method + * returns null. + * @return repository workspace + */ + public String getRepositoryWorkspaceId(); + + /** + * setInput is used to set (multipart) request input before starting to + * process input data + * @param input multipart data input + * @exception IOException + */ + public void setInput(MultipartInput input) throws IOException; + + /** + * Get input parts as received over the wire from service consumer + * @return the input + */ + public MultipartInput getInput(); + + /** + * Get output parts to send over the wire to service consumer + * @return the output + */ + public MultipartOutput getOutput(); + + /** + * getInputPart returns part for given label from input + * @param label + * @param clazz class of the object + * @return part + */ + public Object getInputPart(String label, Class clazz) throws IOException; + + /** + * addOutputPart adds given XML part with given label and content type to output + * @param label + * @param document + * @param contentType media type + */ + public void addOutputPart(String label, Document doc, String contentType) throws Exception; + + /** + * getPartsMetadata returns metadata for object parts used by the service + * @return + */ + public Map getPartsMetadata(); + + /** + * getCommonPartLabel retruns label for common part of a service + * @return label + */ + public String getCommonPartLabel(); +} + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextImpl.java b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextImpl.java new file mode 100644 index 000000000..b88a6a7e0 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextImpl.java @@ -0,0 +1,239 @@ +/** + * 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.common.context; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.MediaType; +import org.collectionspace.services.common.ClientType; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.config.TenantBindingConfigReader; +import org.collectionspace.services.common.repository.DocumentUtils; +import org.collectionspace.services.common.service.ObjectPartType; +import org.collectionspace.services.common.service.ServiceBindingType; +import org.collectionspace.services.common.service.ServiceObjectType; +import org.collectionspace.services.common.tenant.TenantBindingType; +import org.jboss.resteasy.plugins.providers.multipart.InputPart; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; +import org.jboss.resteasy.plugins.providers.multipart.OutputPart; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +/** + * ServiceContextImpl + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class ServiceContextImpl + implements ServiceContext { + + final Logger logger = LoggerFactory.getLogger(ServiceContextImpl.class); + private TenantBindingType tenantBinding; + private ServiceBindingType serviceBinding; + //input stores original content as received over the wire + private MultipartInput input; + private MultipartOutput output; + Map objectPartMap = new HashMap(); + + @Override + public String toString() { + return "ServiceContextImpl [" + + "service name=" + serviceBinding.getName() + " " + + "service version=" + serviceBinding.getVersion() + " " + + "tenant id=" + tenantBinding.getId() + " " + + "tenant name=" + tenantBinding.getName() + " " + tenantBinding.getDisplayName() + " " + + "tenant repository domain=" + tenantBinding.getRepositoryDomain() + " " + + "]"; + } + + public ServiceContextImpl(String serviceName) { + TenantBindingConfigReader tReader = + ServiceMain.getInstance().getTenantBindingConfigReader(); + //TODO: get tenant binding from security context (Subject.g + String tenantId = "1"; //hardcoded for movingimages.us + tenantBinding = tReader.getTenantBinding(tenantId); + if(tenantBinding == null){ + String msg = "No tenant binding found while processing request for " + + serviceName; + logger.error(msg); + throw new IllegalStateException(msg); + } + serviceBinding = tReader.getServiceBinding(tenantId, serviceName); + if(serviceBinding == null){ + String msg = "No service binding found while processing request for " + + serviceName + " for tenant id=" + getTenantId() + + " name=" + getTenantName(); + logger.error(msg); + throw new IllegalStateException(msg); + } + if(logger.isDebugEnabled()){ + logger.debug("tenantId=" + tenantId + + " service binding=" + serviceBinding.getName()); + } + output = new MultipartOutput(); + } + + @Override + public String getTenantId() { + return tenantBinding.getId(); + } + + @Override + public String getTenantName() { + return tenantBinding.getName(); + } + + @Override + public ServiceBindingType getServiceBinding() { + return serviceBinding; + } + + @Override + public String getServiceName() { + return serviceBinding.getName(); + } + + @Override + public String getQualifiedServiceName() { + return TenantBindingConfigReader.getTenantQualifiedServiceName( + getTenantId(), getServiceName()); + } + + @Override + public String getRepositoryDomainName() { + return tenantBinding.getRepositoryDomain(); + } + + @Override + public String getRepositoryClientName() { + return serviceBinding.getRepositoryClient(); + } + + @Override + public ClientType getRepositoryClientType() { + //assumption: there is only one repository client configured + return ServiceMain.getInstance().getClientType(); + } + + @Override + public String getRepositoryWorkspaceName() { + //service name is workspace name by convention + return serviceBinding.getName(); + } + + @Override + public String getRepositoryWorkspaceId() { + TenantBindingConfigReader tbConfigReader = + ServiceMain.getInstance().getTenantBindingConfigReader(); + return tbConfigReader.getWorkspaceId(getTenantId(), getServiceName()); + } + + @Override + public MultipartInput getInput() { + return input; + } + + @Override + public MultipartOutput getOutput() { + return output; + } + + @Override + public Object getInputPart(String label, Class clazz) throws IOException { + Object obj = null; + if(getInput() != null){ + MultipartInput fdip = getInput(); + + for(InputPart part : fdip.getParts()){ + String partLabel = part.getHeaders().getFirst("label"); + if(label.equalsIgnoreCase(partLabel)){ + if(logger.isDebugEnabled()){ + logger.debug("received part label=" + partLabel + + "\npayload=" + part.getBodyAsString()); + } + obj = part.getBody(clazz, null); + break; + } + } + } + return obj; + } + + @Override + public void addOutputPart(String label, Document doc, String contentType) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try{ + DocumentUtils.writeDocument(doc, baos); + baos.close(); + OutputPart part = output.addPart(new String(baos.toByteArray()), + MediaType.valueOf(contentType)); + part.getHeaders().add("label", label); + }finally{ + if(baos != null){ + try{ + baos.close(); + }catch(Exception e){ + } + } + } + } + + @Override + public void setInput(MultipartInput input) throws IOException { + this.input = input; + } + + @Override + public Map getPartsMetadata() { + if(objectPartMap.size() != 0){ + return objectPartMap; + } + + ServiceBindingType serviceBinding = getServiceBinding(); + List objectTypes = serviceBinding.getObject(); + for(ServiceObjectType objectType : objectTypes){ + List objectPartTypes = objectType.getPart(); + for(ObjectPartType objectPartType : objectPartTypes){ + objectPartMap.put(objectPartType.getLabel(), objectPartType); + } + + } + return objectPartMap; + } + + /** + * getCommonPartLabel get common part label + * @return + */ + @Override + public String getCommonPartLabel() { + return getServiceName().toLowerCase() + "-common"; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/AbstractDocumentHandler.java b/services/common/src/main/java/org/collectionspace/services/common/repository/AbstractDocumentHandler.java new file mode 100644 index 000000000..367def58f --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/AbstractDocumentHandler.java @@ -0,0 +1,188 @@ +/** + * 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.common.repository; + +import java.util.HashMap; +import java.util.Map; + +import java.util.StringTokenizer; +import org.collectionspace.services.common.context.ServiceContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * AbstractDocumentHandler + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public abstract class AbstractDocumentHandler + implements DocumentHandler { + + private final Logger logger = LoggerFactory.getLogger(AbstractDocumentHandler.class); + private Map properties = new HashMap(); + private ServiceContext serviceContext; + + public AbstractDocumentHandler() { + } + + @Override + public ServiceContext getServiceContext() { + return serviceContext; + } + + @Override + public void setServiceContext(ServiceContext ctx) { + serviceContext = ctx; + } + + /** + * @return the properties + */ + @Override + public Map getProperties() { + return properties; + } + + /** + * @param properties the properties to set + */ + @Override + public void setProperties(Map properties) { + this.properties = properties; + } + + @Override + public void prepare(Action action) throws Exception { + //no specific action needed + } + + @Override + public void handle(Action action, DocumentWrapper wrapDoc) throws Exception { + switch(action){ + case CREATE: + handleCreate(wrapDoc); + break; + + case UPDATE: + handleUpdate(wrapDoc); + break; + + case GET: + handleGet(wrapDoc); + break; + + case GET_ALL: + handleGetAll(wrapDoc); + break; + + } + } + + @Override + public abstract void handleCreate(DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract void handleUpdate(DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract void handleGet(DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract void handleGetAll(DocumentWrapper wrapDoc) throws Exception; + + @Override + public void complete(Action action, DocumentWrapper wrapDoc) throws Exception { + switch(action){ + //TODO: add more actions if needed + case UPDATE: + completeUpdate(wrapDoc); + break; + } + } + + @Override + public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { + //no specific action needed + } + + @Override + public abstract void extractAllParts(DocumentWrapper wrapDoc) + throws Exception; + + @Override + public abstract void fillAllParts(DocumentWrapper wrapDoc) + throws Exception; + + @Override + public abstract T extractCommonPart(DocumentWrapper wrapDoc) + throws Exception; + + @Override + public abstract void fillCommonPart(T obj, DocumentWrapper wrapDoc) + throws Exception; + + @Override + public abstract TL extractCommonPartList(DocumentWrapper wrapDoc) + throws Exception; + + @Override + final public void fillCommonPartList(TL obj, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException("bulk create/update not yet supported"); + } + + @Override + public abstract T getCommonPart(); + + @Override + public abstract void setCommonPart(T obj); + + @Override + public abstract TL getCommonPartList(); + + @Override + public abstract void setCommonPartList(TL obj); + + @Override + public abstract String getQProperty(String prop); + + @Override + public String getUnQProperty(String qProp) { + StringTokenizer tkz = new StringTokenizer(qProp, ":"); + if(tkz.countTokens() != 2){ + String msg = "Property must be in the form xxx:yyy, " + + "e.g. collectionobjects-common:objectNumber"; + logger.error(msg); + throw new IllegalArgumentException(msg); + } + tkz.nextToken(); //skip + return tkz.nextToken(); + } + + @Override + public String getServiceContextPath() { + return "/" + getServiceContext().getServiceName().toLowerCase() + "/"; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java index 39043b068..826b7eb03 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java @@ -20,7 +20,7 @@ package org.collectionspace.services.common.repository; /** * DocumentException - * Nuxeo document handling exception + * document handling exception */ public class DocumentException extends Exception { diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java index f3f3e2512..5afe00bcb 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java @@ -17,15 +17,17 @@ */ package org.collectionspace.services.common.repository; -import org.collectionspace.services.common.repository.DocumentWrapper; -import org.collectionspace.services.common.repository.DocumentException; +import java.io.IOException; import java.util.Map; -import org.dom4j.Document; +import org.collectionspace.services.common.context.ServiceContext; +import org.w3c.dom.Document; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; /** * * DocumentHandler provides document processing methods. It is an interface - * between Nuxeo repository client and CollectionSpace service resource. It provides + * between repository client and CollectionSpace service resource. It provides * methods to setup request via repository client and handle its response. * * Typical call sequence is: @@ -43,8 +45,26 @@ public interface DocumentHandler { } /** - * prepare is called by the Nuxeo client to prepare required parameters to set - * before invoking repository operation. this is mainly useful for create and + * getServiceContext returns service context + * @return + */ + public ServiceContext getServiceContext(); + + /** + * getServiceContextPath such as "/collectionobjects/" + * @return + */ + public String getServiceContextPath(); + + /** + * setServiceContext sets service contex to the handler + * @param ctx + */ + public void setServiceContext(ServiceContext ctx); + + /** + * prepare is called by the client for preparation of stuff before + * invoking repository operation. this is mainly useful for create and * update kind of actions * @param action * @throws Exception @@ -52,108 +72,117 @@ public interface DocumentHandler { public void prepare(Action action) throws Exception; /** - * handle is called by the Nuxeo client to hand over the document processing on create - * function to the CollectionSpace service + * handle is called by the client to hand over the document processing task * @param action - * @param doc wrapped Nuxeo doc + * @param doc wrapped doc * @throws Exception */ public void handle(Action action, DocumentWrapper docWrap) throws Exception; - /** - * handleCreate processes create operation response + /** + * handleCreate processes documents before creating document in repository * @param wrapDoc * @throws Exception */ public void handleCreate(DocumentWrapper wrapDoc) throws Exception; /** - * handleUpdate processes update operation response + * handleUpdate processes documents for the update of document in repository * @param wrapDoc * @throws Exception */ public void handleUpdate(DocumentWrapper wrapDoc) throws Exception; /** - * handleGet processes get operation response + * handleGet processes documents from repository before responding to consumer * @param wrapDoc * @throws Exception */ public void handleGet(DocumentWrapper wrapDoc) throws Exception; /** - * handleGetAll processes index operation response + * handleGetAll processes documents from repository before responding to consumer * @param wrapDoc * @throws Exception */ public void handleGetAll(DocumentWrapper wrapDoc) throws Exception; - + /** - * extractCommonObject extracts common part of a CS document from given Nuxeo document. - * @param docWrap nuxeo document - * @return common part of CS object + * complete is called by the client to provide an opportunity to the handler + * to take care of stuff before closing session with the repository. example + * could be to reclaim resources or to populate response to the consumer + * @param wrapDoc * @throws Exception */ - public T extractCommonObject(DocumentWrapper docWrap) throws Exception; + public void complete(Action action, DocumentWrapper wrapDoc) throws Exception; /** - * fillCommonObject sets common part of CS object into given Nuxeo document - * @param obj input object - * @param docWrap target Nuxeo document + * completeUpdate is called by the client to indicate completion of the update call. + * this gives opportunity to prepare updated object that should be sent back to the consumer + * @param wrapDoc * @throws Exception */ - public void fillCommonObject(T obj, DocumentWrapper docWrap) throws Exception; + public void completeUpdate(DocumentWrapper wrapDoc) throws Exception; - /** - * extractCommonObject extracts common part of a CS document from given Nuxeo document. - * @param docWrap nuxeo document - * @return common part of CS object + /** + * extractAllParts extracts all parts of a CS object from given document. + * this is usually called AFTER the get operation is invoked on the repository + * Called in handle GET/GET_ALL actions. + * @param docWrap document * @throws Exception */ - public TL extractCommonObjectList(DocumentWrapper docWrap) throws Exception; + public void extractAllParts(DocumentWrapper docWrap) throws Exception; /** - * fillCommonObject sets common part of CS object into given Nuxeo document + * fillAllParts sets parts of CS object into given document + * this is usually called BEFORE create/update operations are invoked on the + * repository. Called in handle CREATE/UPDATE actions. * @param obj input object - * @param docWrap target Nuxeo document + * @param docWrap target document * @throws Exception */ - public void fillCommonObjectList(TL obj, DocumentWrapper docWrap) throws Exception; + public void fillAllParts(DocumentWrapper docWrap) throws Exception; /** - * getCommonObject provides the common part of a CS document. - * @return common part of CS document + * extractCommonPart extracts common part of a CS object from given document. + * this is usually called AFTER the get operation is invoked on the repository. + * Called in handle GET/GET_ALL actions. + * @param docWrap document + * @return common part of CS object + * @throws Exception */ - public T getCommonObject(); + public T extractCommonPart(DocumentWrapper docWrap) throws Exception; /** - * setCommonObject sets common part of CS document as input for operation on - * Nuxeo repository + * fillCommonPart sets common part of CS object into given document + * this is usually called BEFORE create/update operations are invoked on the + * repository. Called in handle CREATE/UPDATE actions. * @param obj input object + * @param docWrap target document + * @throws Exception */ - public void setCommonObject(T obj); + public void fillCommonPart(T obj, DocumentWrapper docWrap) throws Exception; /** - * getCommonObjectList provides the default list object of a CS document. - * @return default list of CS document + * extractCommonPart extracts common part of a CS object from given document. + * this is usually called AFTER bulk get (index/list) operation is invoked on + * the repository + * @param docWrap document + * @return common part of CS object + * @throws Exception */ - public TL getCommonObjectList(); + public TL extractCommonPartList(DocumentWrapper docWrap) throws Exception; /** - * setCommonObjectList sets default list object for CS document as input for operation on - * Nuxeo repository - * @param default list of CS document + * fillCommonPartList sets list common part of CS object into given document + * this is usually called BEFORE bulk create/update on the repository + * (not yet supported) + * @param obj input object + * @param docWrap target document + * @throws Exception */ - public void setCommonObjectList(TL obj); + public void fillCommonPartList(TL obj, DocumentWrapper docWrap) throws Exception; - /** - * getDocument get org.dom4j.Document from given DocumentModel - * @param Nuxeo document wrapper - * @return - * @throws DocumentException - */ - public Document getDocument(DocumentWrapper docWrap) throws DocumentException; - /** * Gets the document type. * @@ -169,8 +198,48 @@ public interface DocumentHandler { /** * setProperties provides means to the CollectionSpace service resource to - * set up parameters before invoking create request via the Nuxeo client. + * set up parameters before invoking any request via the client. * @param properties */ public void setProperties(Map properties); + + /** + * getCommonPart provides the common part of a CS object. + * @return common part of CS object + */ + public T getCommonPart(); + + /** + * setCommonPart sets common part of CS object as input for operation on + * repository + * @param obj input object + */ + public void setCommonPart(T obj); + + /** + * getCommonPartList provides the default list object of a CS object. + * @return default list of CS object + */ + public TL getCommonPartList(); + + /** + * setCommonPartList sets common part list entry for CS object as input for operation on + * repository + * @param default list of CS object + */ + public void setCommonPartList(TL obj); + + /** + * getQProperty get qualified property (useful for mapping to repository document property) + * @param prop + * @return + */ + public String getQProperty(String prop); + + /** + * getUnQProperty unqualifies document property from repository + * @param qProp qualifeid property + * @return unqualified property + */ + public String getUnQProperty(String qProp); } diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java new file mode 100644 index 000000000..25608423b --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java @@ -0,0 +1,172 @@ +/** + * 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.common.repository; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.collectionspace.services.common.service.ObjectPartContentType; +import org.collectionspace.services.common.service.ObjectPartType; +import org.collectionspace.services.common.service.XmlContentType; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +/** +* DocumentUtils is a collection of utilities related to document management +* +* $LastChangedRevision: $ +* $LastChangedDate: $ +*/ +public class DocumentUtils { + + /** + * parseProperties given payload to create XML document. this + * method also closes given stream after parsing. + * @param payload stream + * @return parsed Document + * @throws Exception + */ + public static Document parseDocument(InputStream payload) + throws Exception { + try{ + // Create a builder factory + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setValidating(false);//TODO take validating value from meta + + // Create the builder and parse the file + return factory.newDocumentBuilder().parse(payload); + + }finally{ + if(payload != null){ + payload.close(); + } + + } + } + + /** + * parseProperties extract given payload (XML) into Name-Value properties. this + * @param document to parse + * @return map key=property name, value=property value + * @throws Exception + */ + public static Map parseProperties(Document document) + throws Exception { + HashMap objectProps = new HashMap(); + // Get a list of all elements in the document + Node root = document.getFirstChild(); + NodeList children = root.getChildNodes(); + for(int i = 0; i < children.getLength(); i++){ + Node node = (Node) children.item(i); + if(node.getNodeType() == Node.ELEMENT_NODE){ + Node cnode = node.getFirstChild(); + if(cnode.getNodeType() != Node.TEXT_NODE){ + continue; + } + Node textNode = (Text) cnode; + objectProps.put(node.getNodeName(), + textNode.getNodeValue()); + } + } + return objectProps; + } + + /** + * buildDocument builds org.w3c.dom.Document from given properties using + * given metadata for a part + * @param partMeta + * @param rootElementName + * @param objectProps + * @return + * @throws Exception + */ + public static Document buildDocument(ObjectPartType partMeta, String rootElementName, + Map objectProps) + throws Exception { + ObjectPartContentType partContentMeta = partMeta.getContent(); + XmlContentType xc = partContentMeta.getXmlContent(); + if(xc == null){ + return null; + } + + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document document = builder.newDocument(); + document.setXmlStandalone(true); + //JAXB unmarshaller recognizes the following kind of namespace qualification + //only. More investigation is needed to use other prefix +// +// +// objectNumber-1252960222412 +// objectName-1252960222412 +// + + String ns = "ns2"; + Element root = document.createElementNS(xc.getNamespaceURI(), ns + ":" + rootElementName); + root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + root.setAttribute("xsi:schemaLocation", xc.getSchemaLocation()); + root.setAttribute("xmlns:" + ns, xc.getNamespaceURI()); + document.appendChild(root); + + for(String prop : objectProps.keySet()){ + Object value = objectProps.get(prop); + if(value != null){ + //no need to qualify each element name as namespace is already added + Element e = document.createElement(prop); + root.appendChild(e); + String strValue = objectProps.get(prop).toString(); + Text tNode = document.createTextNode(strValue); + e.appendChild(tNode); + } + } + return document; + } + + /** + * writeDocument streams out given document to given output stream + * @param document + * @param os + * @throws Exception + */ + public static void writeDocument(Document document, OutputStream os) throws Exception { + TransformerFactory tFactory = + TransformerFactory.newInstance(); + Transformer transformer = tFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + DOMSource source = new DOMSource(document); + StreamResult result = new StreamResult(os); + transformer.transform(source, result); + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java index 433db1f0c..d2bfa6bdb 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java @@ -23,6 +23,8 @@ */ package org.collectionspace.services.common.repository; +import org.collectionspace.services.common.context.ServiceContext; + /** * RepositoryClient is a generic Document Repository client @@ -38,52 +40,50 @@ public interface RepositoryClient { /** * create document in the Document repository - * @param serviceName entity service for which document is created. for example - * this is used to find mapping - * to a Nuxeo workspace using service-config.xml - * @param serviceName entity service for which document is created. this is used to find mapping - * to a Nuxeo workspace using service-config.xml + * @param ctx service context under which this method is invoked * @param handler should be used by the caller to provide and transform the document * @return id in repository of the newly created document * @throws BadRequestException data input is bad * @throws DocumentException */ - String create(String serviceName, DocumentHandler handler) throws BadRequestException, DocumentException; + String create(ServiceContext ctx, DocumentHandler handler) throws BadRequestException, DocumentException; /** * delete a document from the Document repository + * @param ctx service context under which this method is invoked * @param id of the document * @throws DocumentNotFoundException if document not found * @throws DocumentException */ - void delete(String id) throws DocumentNotFoundException, DocumentException; + void delete(ServiceContext ctx, String id) throws DocumentNotFoundException, DocumentException; /** * get document from the Document repository + * @param ctx service context under which this method is invoked * @param id of the document to retrieve * @param handler should be used by the caller to provide and transform the document * @throws DocumentNotFoundException if document not found * @throws DocumentException */ - void get(String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; /** * getAll get all documents for an entity entity service from the Document repository - * @param serviceName entity service for which documents are retrieved. this is used to find mapping - * to a Nuxeo workspace using service-config.xml + * @param ctx service context under which this method is invoked * @param handler should be used by the caller to provide and transform the document * @throws DocumentNotFoundException if workspace not found * @throws DocumentException */ - void getAll(String serviceName, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + void getAll(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; /** * update given document in the Document repository + * @param ctx service context under which this method is invoked * @param id of the document * @param handler should be used by the caller to provide and transform the document * @throws BadRequestException data input is bad * @throws DocumentNotFoundException if document not found * @throws DocumentException */ - void update(String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException; + void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java index c14549322..0159fc0e8 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java @@ -23,33 +23,39 @@ */ package org.collectionspace.services.common.repository; +import java.lang.ClassLoader; import java.util.Hashtable; -import org.collectionspace.services.common.NuxeoClientType; +import org.collectionspace.services.common.RepositoryClientConfigType; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.config.ServicesConfigReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * RepositoryClientFactory is a singleton factory that provides required Nuxeo client - * it does not create clients as the clients are singletons + * RepositoryClientFactory is a singleton factory that creates required repository + * clients. Repository clients are singletons. * * $LastChangedRevision: $ * $LastChangedDate: $ */ public class RepositoryClientFactory { - private static final RepositoryClientFactory self = new RepositoryClientFactory(); + final Logger logger = LoggerFactory.getLogger(RepositoryClientFactory.class); + //clients key=client name, value=repository client private Hashtable clients = new Hashtable(); private RepositoryClientFactory() { try{ + ServicesConfigReader scReader = ServiceMain.getInstance().getServicesConfigReader(); + RepositoryClientConfigType repositoryClientConfig = scReader.getConfiguration().getRepositoryClient(); + String clientClassName = repositoryClientConfig.getClientClass(); + String clientName = repositoryClientConfig.getName(); ClassLoader cloader = Thread.currentThread().getContextClassLoader(); - Class jclazz = cloader.loadClass("org.collectionspace.services.nuxeo.client.java.RepositoryJavaClient"); + Class jclazz = cloader.loadClass(clientClassName); Object jclient = jclazz.newInstance(); - clients.put(NuxeoClientType.JAVA.toString(), (RepositoryClient) jclient); - - Class rclazz = cloader.loadClass("org.collectionspace.services.nuxeo.client.rest.RepositoryRESTClient"); - Object rclient = rclazz.newInstance(); - clients.put(NuxeoClientType.REST.toString(), (RepositoryClient) rclient); + clients.put(clientName, (RepositoryClient) jclient); }catch(Exception e){ throw new RuntimeException(e); @@ -60,7 +66,12 @@ public class RepositoryClientFactory { return self; } - public RepositoryClient getClient(String clientType) { - return clients.get(clientType); + /** + * get repository client + * @param clientName name of the client as found in service binding + * @return + */ + public RepositoryClient getClient(String clientName) { + return clients.get(clientName); } } diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java index 3bb10b395..977d31b31 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java @@ -23,18 +23,26 @@ */ package org.collectionspace.services.nuxeo.client.java; -import org.collectionspace.services.common.repository.DocumentHandler; -import org.collectionspace.services.common.repository.DocumentWrapper; -import org.collectionspace.services.common.repository.DocumentException; +import java.io.InputStream; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import javax.ws.rs.core.MediaType; +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.collectionspace.services.common.repository.AbstractDocumentHandler; +import org.collectionspace.services.common.repository.BadRequestException; +import org.collectionspace.services.common.repository.DocumentUtils; +import org.collectionspace.services.common.service.ObjectPartType; import org.collectionspace.services.nuxeo.client.*; -import org.collectionspace.services.nuxeo.util.NuxeoUtils; -import org.dom4j.Document; +import org.jboss.resteasy.plugins.providers.multipart.InputPart; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.repository.RepositoryInstance; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; /** * DocumentModelHandler is a base abstract Nuxeo document handler @@ -44,132 +52,170 @@ import org.slf4j.LoggerFactory; * $LastChangedDate: $ */ public abstract class DocumentModelHandler - implements DocumentHandler { + extends AbstractDocumentHandler { private final Logger logger = LoggerFactory.getLogger(DocumentModelHandler.class); - private Map properties = new HashMap(); private RepositoryInstance repositorySession; + //key=schema, value=documentpart - @Override - public abstract void prepare(Action action) throws Exception; + /** + * getRepositorySession returns Nuxeo Repository Session + * @return + */ + public RepositoryInstance getRepositorySession() { + return repositorySession; + } - @Override - public void handle(Action action, DocumentWrapper wrapDoc) throws Exception { - switch(action){ - case CREATE: - handleCreate(wrapDoc); - break; - case UPDATE: - handleUpdate(wrapDoc); - break; - case GET: - handleGet(wrapDoc); - break; - case GET_ALL: - handleGetAll(wrapDoc); - break; - } + /** + * setRepositorySession sets repository session + * @param repoSession + */ + public void setRepositorySession(RepositoryInstance repoSession) { + this.repositorySession = repoSession; } @Override public void handleCreate(DocumentWrapper wrapDoc) throws Exception { - if(getCommonObject() == null){ - String msg = "Error creating document: Missing input data"; - logger.error(msg); - throw new IllegalStateException(msg); - } - //FIXME set other parts as well - fillCommonObject(getCommonObject(), wrapDoc); + fillAllParts(wrapDoc); } @Override public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { - if(getCommonObject() == null){ - String msg = "Error updating document: Missing input data"; - logger.error(msg); - throw new IllegalStateException(msg); - } - //FIXME set other parts as well - fillCommonObject(getCommonObject(), wrapDoc); + fillAllParts(wrapDoc); } @Override public void handleGet(DocumentWrapper wrapDoc) throws Exception { - setCommonObject(extractCommonObject(wrapDoc)); - - //FIXME retrive other parts as well + extractAllParts(wrapDoc); } @Override public void handleGetAll(DocumentWrapper wrapDoc) throws Exception { - setCommonObjectList(extractCommonObjectList(wrapDoc)); + setCommonPartList(extractCommonPartList(wrapDoc)); } - /** - * getRepositorySession returns Nuxeo Repository Session - * @return - */ - public RepositoryInstance getRepositorySession() { - return repositorySession; + @Override + public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + //return at least those document part(s) that were received + Map partsMetaMap = getServiceContext().getPartsMetadata(); + List inputParts = getServiceContext().getInput().getParts(); + for(InputPart part : inputParts){ + String partLabel = part.getHeaders().getFirst("label"); + ObjectPartType partMeta = partsMetaMap.get(partLabel); + extractObject(docModel, partLabel, partMeta); + } } - /** - * setRepositorySession sets repository session - * @param repoSession - */ - public void setRepositorySession(RepositoryInstance repoSession) { - this.repositorySession = repoSession; + @Override + public void extractAllParts(DocumentWrapper wrapDoc) throws Exception { + + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + String[] schemas = docModel.getDeclaredSchemas(); + Map partsMetaMap = getServiceContext().getPartsMetadata(); + for(String schema : schemas){ + ObjectPartType partMeta = partsMetaMap.get(schema); + if(partMeta == null){ + continue; //unknown part, ignore + } + extractObject(docModel, schema, partMeta); + } } @Override - public abstract T extractCommonObject(DocumentWrapper wrapDoc) throws Exception; + public abstract T extractCommonPart(DocumentWrapper wrapDoc) throws Exception; @Override - public abstract void fillCommonObject(T obj, DocumentWrapper wrapDoc) throws Exception; + public void fillAllParts(DocumentWrapper wrapDoc) throws Exception { - @Override - public abstract TL extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception; + //TODO filling extension parts should be dynamic + //Nuxeo APIs lack to support stream/byte[] input, get/setting properties is + //not an ideal way of populating objects. + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + MultipartInput input = getServiceContext().getInput(); + if(input.getParts().isEmpty()){ + String msg = "No payload found!"; + logger.error(msg + "Ctx=" + getServiceContext().toString()); + throw new BadRequestException(msg); + } + + Map partsMetaMap = getServiceContext().getPartsMetadata(); + + //iterate over parts received and fill those parts + List inputParts = input.getParts(); + for(InputPart part : inputParts){ + + String partLabel = part.getHeaders().getFirst("label"); + //skip if the part is not in metadata + if(!partsMetaMap.containsKey(partLabel)){ + continue; + } + InputStream payload = part.getBody(InputStream.class, null); + + //check if this is an xml part + if(part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)){ + if(payload != null){ + Document document = DocumentUtils.parseDocument(payload); + //TODO: callback to handler if registered to validate the + //document + Map objectProps = DocumentUtils.parseProperties(document); + docModel.setProperties(partLabel, objectProps); + } + } + }//rof + + } @Override - public abstract void fillCommonObjectList(TL obj, DocumentWrapper wrapDoc) throws Exception; + public abstract void fillCommonPart(T obj, DocumentWrapper wrapDoc) throws Exception; @Override - public abstract T getCommonObject(); + public abstract TL extractCommonPartList(DocumentWrapper wrapDoc) throws Exception; @Override - public abstract void setCommonObject(T obj); + public abstract T getCommonPart(); @Override - public abstract TL getCommonObjectList(); + public abstract void setCommonPart(T obj); @Override - public abstract void setCommonObjectList(TL obj); + public abstract TL getCommonPartList(); @Override - public Document getDocument(DocumentWrapper wrapDoc) throws DocumentException { - DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); - return NuxeoUtils.getDocument(getRepositorySession(), docModel); - } - + public abstract void setCommonPartList(TL obj); + /* (non-Javadoc) * @see org.collectionspace.services.common.repository.DocumentHandler#getDocumentType() */ @Override public abstract String getDocumentType(); - - /** - * @return the properties - */ - @Override - public Map getProperties() { - return properties; - } /** - * @param properties the properties to set + * extractObject extracts an XML object from given DocumentModel + * @param docModel + * @param schema of the object to extract + * @param partMeta metadata for the object to extract + * @throws Exception */ - @Override - public void setProperties(Map properties) { - this.properties = properties; + protected void extractObject(DocumentModel docModel, String schema, ObjectPartType partMeta) + throws Exception { + MediaType mt = MediaType.valueOf(partMeta.getContent().getContentType()); + if(mt.equals(MediaType.APPLICATION_XML_TYPE)){ + Map objectProps = docModel.getProperties(schema); + //unqualify properties before sending the doc over the wire (to save bandwidh) + //FIXME: is there a better way to avoid duplication of a collection? + Map unQObjectProperties = new HashMap(); + Set> qualifiedEntries = objectProps.entrySet(); + for(Entry entry : qualifiedEntries){ + String unqProp = getUnQProperty(entry.getKey()); + unQObjectProperties.put(unqProp, entry.getValue()); + } + Document doc = DocumentUtils.buildDocument(partMeta, schema, unQObjectProperties); + if(logger.isDebugEnabled()){ + DocumentUtils.writeDocument(doc, System.out); + } + getServiceContext().addOutputPart(schema, doc, partMeta.getContent().getContentType()); + } //TODO: handle other media types } + } diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java index adde28f86..de56a8a57 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java @@ -27,7 +27,7 @@ import java.io.File; import java.util.Collection; import java.util.Hashtable; import java.util.Iterator; -import org.collectionspace.services.common.ServiceConfig.NuxeoClientConfig; +import org.collectionspace.services.common.RepositoryClientConfigType; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.repository.RepositoryInstance; @@ -48,7 +48,7 @@ public class NuxeoConnector { private NuxeoApp app; private NuxeoClient client; private volatile boolean initialized = false; //use volatile for lazy initialization in singleton - private NuxeoClientConfig nuxeoClientConfig; + private RepositoryClientConfigType repositoryClientConfig; private NuxeoConnector() { } @@ -62,17 +62,17 @@ public class NuxeoConnector { * is initialized in a thread-safe manner and not initialized more than once. * Initialization involves starting Nuxeo runtime, loading Nuxeo APIs jars * in OSGI container as well as establishing initial connection. - * @param nuxeoClientConfig + * @param repositoryClientConfig * @throws java.lang.Exception */ - public void initialize(NuxeoClientConfig nuxeoClientConfig) throws Exception { + public void initialize(RepositoryClientConfigType repositoryClientConfig) throws Exception { if(initialized == false){ synchronized(this){ if(initialized == false){ try{ - this.nuxeoClientConfig = nuxeoClientConfig; - setProperties(nuxeoClientConfig); + this.repositoryClientConfig = repositoryClientConfig; + setProperties(repositoryClientConfig); app = new NuxeoApp(); app.start(); if(logger.isDebugEnabled()){ @@ -130,13 +130,13 @@ public class NuxeoConnector { } } - private void setProperties(NuxeoClientConfig nuxeoClientConfig) { + private void setProperties(RepositoryClientConfigType repositoryClientConfig) { System.setProperty("nuxeo.client.on.jboss", Boolean.TRUE.toString()); System.setProperty("org.nuxeo.runtime.server.enabled", Boolean.FALSE.toString()); - System.setProperty("org.nuxeo.runtime.server.port", "" + nuxeoClientConfig.getPort()); - System.setProperty("org.nuxeo.runtime.server.host", nuxeoClientConfig.getHost()); + System.setProperty("org.nuxeo.runtime.server.port", "" + repositoryClientConfig.getPort()); + System.setProperty("org.nuxeo.runtime.server.host", repositoryClientConfig.getHost()); //System.setProperty("org.nuxeo.runtime.1.3.3.streaming.port", "3233"); - System.setProperty("org.nuxeo.runtime.streaming.serverLocator", "socket://" + nuxeoClientConfig.getHost() + ":3233"); + System.setProperty("org.nuxeo.runtime.streaming.serverLocator", "socket://" + repositoryClientConfig.getHost() + ":3233"); System.setProperty("org.nuxeo.runtime.streaming.isServer", Boolean.FALSE.toString()); //org.nuxeo.client.remote is part of the fix to Nuxeo Runtime to use Java Remote APIs //from JBoss @@ -156,10 +156,10 @@ public class NuxeoConnector { // }else{ //authentication failure error comes when reusing the client //force connect for now - client.forceConnect(nuxeoClientConfig.getHost(), nuxeoClientConfig.getPort()); + client.forceConnect(repositoryClientConfig.getHost(), repositoryClientConfig.getPort()); if(logger.isDebugEnabled()){ logger.debug("getClient(): connection successful port=" + - nuxeoClientConfig.getPort()); + repositoryClientConfig.getPort()); } return client; // } @@ -199,23 +199,31 @@ public class NuxeoConnector { /** * retrieveWorkspaceIds retrieves all workspace ids from default repository - * @return + * @param tenantDomain domain representing tenant + * @return * @throws java.lang.Exception */ - public Hashtable retrieveWorkspaceIds() throws Exception { + public Hashtable retrieveWorkspaceIds(String tenantDomain) throws Exception { RepositoryInstance repoSession = null; Hashtable workspaceIds = new Hashtable(); try{ repoSession = getRepositorySession(); DocumentModel rootDoc = repoSession.getRootDocument(); DocumentModelList rootChildrenList = repoSession.getChildren(rootDoc.getRef()); - Iterator riter = rootChildrenList.iterator(); - if(riter.hasNext()){ - DocumentModel domain = riter.next(); + Iterator diter = rootChildrenList.iterator(); + while(diter.hasNext()){ + DocumentModel domain = diter.next(); + String domainPath = "/" + tenantDomain; + if(!domain.getPathAsString().equalsIgnoreCase(domainPath)) { + continue; + } + if(logger.isDebugEnabled()) { + logger.debug("domain=" + domain.toString()); + } DocumentModelList domainChildrenList = repoSession.getChildren(domain.getRef()); - Iterator diter = domainChildrenList.iterator(); - while(diter.hasNext()){ - DocumentModel childNode = diter.next(); + Iterator witer = domainChildrenList.iterator(); + while(witer.hasNext()){ + DocumentModel childNode = witer.next(); if("Workspaces".equalsIgnoreCase(childNode.getName())){ DocumentModelList workspaceList = repoSession.getChildren(childNode.getRef()); Iterator wsiter = workspaceList.iterator(); diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java index 330661c07..afa816048 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java @@ -18,7 +18,7 @@ package org.collectionspace.services.nuxeo.client.java; import org.collectionspace.services.common.repository.RepositoryClient; -import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.repository.BadRequestException; import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.common.repository.DocumentHandler; @@ -30,6 +30,7 @@ import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.DocumentRef; import org.nuxeo.ecm.core.api.IdRef; +import org.nuxeo.ecm.core.api.PathRef; import org.nuxeo.ecm.core.api.repository.RepositoryInstance; import org.nuxeo.ecm.core.client.NuxeoClient; import org.slf4j.Logger; @@ -44,308 +45,304 @@ import org.slf4j.LoggerFactory; */ public class RepositoryJavaClient implements RepositoryClient { - private final Logger logger = LoggerFactory - .getLogger(RepositoryJavaClient.class); + private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClient.class); - public RepositoryJavaClient() { - } + public RepositoryJavaClient() { + } - /** - * create document in the Nuxeo repository - * - * @param serviceName - * entity service for which document is created. this is used to - * find mapping to a Nuxeo workspace using service-config.xml - * @param docType - * of the document created - * @param handler - * should be used by the caller to provide and transform the - * document - * @return id in repository of the newly created document - * @throws DocumentException - */ - @Override - public String create(String serviceName, - DocumentHandler handler) throws BadRequestException, - DocumentException { + /** + * create document in the Nuxeo repository + * + * @param ctx service context under which this method is invoked + * @param docType + * of the document created + * @param handler + * should be used by the caller to provide and transform the + * document + * @return id in repository of the newly created document + * @throws DocumentException + */ + @Override + public String create(ServiceContext ctx, + DocumentHandler handler) throws BadRequestException, + DocumentException { - if (serviceName == null) { - throw new IllegalArgumentException( - "RemoteRepositoryClient.create: serviceName is missing"); - } - if (handler.getDocumentType() == null) { - throw new IllegalArgumentException( - "RemoteRepositoryClient.create: docType is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "RemoteRepositoryClient.create: handler is missing"); - } - ServiceMain smain = ServiceMain.getInstance(); - String nuxeoWspaceId = smain.getWorkspaceId(serviceName); - if (nuxeoWspaceId == null) { - throw new DocumentNotFoundException( - "Unable to find workspace for service " - + serviceName - + " check if the mapping exists in service-config.xml or " - + " the the mapped workspace exists in the Nuxeo repository"); - } - RepositoryInstance repoSession = null; - try { - handler.prepare(Action.CREATE); - repoSession = getRepositorySession(); + if(handler.getDocumentType() == null){ + throw new IllegalArgumentException( + "RemoteRepositoryClient.create: docType is missing"); + } + if(handler == null){ + throw new IllegalArgumentException( + "RemoteRepositoryClient.create: handler is missing"); + } + String nuxeoWspaceId = ctx.getRepositoryWorkspaceId(); + if(nuxeoWspaceId == null){ + throw new DocumentNotFoundException( + "Unable to find workspace for service " + ctx.getServiceName() + + " check if the mapping exists in service-config.xml or" + + " the the mapped workspace exists in the Nuxeo repository"); + } + RepositoryInstance repoSession = null; + try{ + handler.prepare(Action.CREATE); + repoSession = getRepositorySession(); + DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId); + DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace); + String wspacePath = wspaceDoc.getPathAsString(); + String id = IdUtils.generateId("New " + handler.getDocumentType()); + // create document model + DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, + handler.getDocumentType()); + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); + handler.handle(Action.CREATE, wrapDoc); + // create document with documentmodel + doc = repoSession.createDocument(doc); + repoSession.save(); + handler.complete(Action.CREATE, wrapDoc); + return doc.getId(); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } - DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId); - DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace); - String wspacePath = wspaceDoc.getPathAsString(); - String id = IdUtils.generateId("New " + handler.getDocumentType()); - // create document model - DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, - handler.getDocumentType()); - ((DocumentModelHandler) handler).setRepositorySession(repoSession); - DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); - handler.handle(Action.CREATE, wrapDoc); - // create document with documentmodel - doc = repoSession.createDocument(doc); - repoSession.save(); - return doc.getId(); - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception ", e); - } - throw new DocumentException(e); - } finally { - if (repoSession != null) { - releaseRepositorySession(repoSession); - } - } + } - } + /** + * get document from the Nuxeo repository + * @param ctx service context under which this method is invoked + * @param id + * of the document to retrieve + * @param handler + * should be used by the caller to provide and transform the + * document + * @throws DocumentException + */ + @Override + public void get(ServiceContext ctx, String id, DocumentHandler handler) + throws DocumentNotFoundException, DocumentException { - /** - * get document from the Nuxeo repository - * - * @param id - * of the document to retrieve - * @param handler - * should be used by the caller to provide and transform the - * document - * @throws DocumentException - */ - @Override - public void get(String id, DocumentHandler handler) - throws DocumentNotFoundException, DocumentException { + if(handler == null){ + throw new IllegalArgumentException( + "RemoteRepositoryClient.get: handler is missing"); + } + RepositoryInstance repoSession = null; - if (handler == null) { - throw new IllegalArgumentException( - "RemoteRepositoryClient.get: handler is missing"); - } - RepositoryInstance repoSession = null; + try{ + handler.prepare(Action.GET); + repoSession = getRepositorySession(); + //FIXME, there is a potential privacy violation here, one tenant could + //retrieve doc id of another tenant and could retrieve the document + //PathRef does not seem to come to rescue as expected. Needs more thoughts. + DocumentRef docRef = new IdRef(id); + DocumentModel doc = null; + try{ + doc = repoSession.getDocument(docRef); + }catch(ClientException ce){ + String msg = "could not find document with id=" + id; + logger.error(msg, ce); + throw new DocumentNotFoundException(msg, ce); + } + //set reposession to handle the document + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); + handler.handle(Action.GET, wrapDoc); + handler.complete(Action.GET, wrapDoc); + }catch(IllegalArgumentException iae){ + throw iae; + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } - try { - handler.prepare(Action.GET); - repoSession = getRepositorySession(); - DocumentRef docRef = new IdRef(id); - DocumentModel doc = null; - try { - doc = repoSession.getDocument(docRef); - } catch (ClientException ce) { - String msg = "could not find document with id=" + id; - logger.error(msg, ce); - throw new DocumentNotFoundException(msg, ce); - } - ((DocumentModelHandler) handler).setRepositorySession(repoSession); - DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); - handler.handle(Action.GET, wrapDoc); - } catch (IllegalArgumentException iae) { - throw iae; - } catch (DocumentException de) { - throw de; - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception ", e); - } - throw new DocumentException(e); - } finally { - if (repoSession != null) { - releaseRepositorySession(repoSession); - } - } - } + /** + * getAll get all documents for an entity entity service from the Nuxeo + * repository + * + * @param ctx service context under which this method is invoked + * @param handler + * should be used by the caller to provide and transform the + * document + * @throws DocumentException + */ + @Override + public void getAll(ServiceContext ctx, DocumentHandler handler) + throws DocumentNotFoundException, DocumentException { + if(handler == null){ + throw new IllegalArgumentException( + "RemoteRepositoryClient.getAll: handler is missing"); + } + String nuxeoWspaceId = ctx.getRepositoryWorkspaceId(); + if(nuxeoWspaceId == null){ + throw new DocumentNotFoundException( + "Unable to find workspace for service " + + ctx.getServiceName() + " check if the mapping exists in service-config.xml or " + + " the the mapped workspace exists in the Nuxeo repository"); + } + RepositoryInstance repoSession = null; - /** - * getAll get all documents for an entity entity service from the Nuxeo - * repository - * - * @param serviceName - * entity service for which documents are retrieved. this is used - * to find mapping to a Nuxeo workspace using service-config.xml - * @param handler - * should be used by the caller to provide and transform the - * document - * @throws DocumentException - */ - @Override - public void getAll(String serviceName, DocumentHandler handler) - throws DocumentNotFoundException, DocumentException { - if (serviceName == null) { - throw new IllegalArgumentException( - "RemoteRepositoryClient.getAll: serviceName is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "RemoteRepositoryClient.getAll: handler is missing"); - } - ServiceMain smain = ServiceMain.getInstance(); - String nuxeoWspaceId = smain.getWorkspaceId(serviceName); - if (nuxeoWspaceId == null) { - throw new DocumentNotFoundException( - "Unable to find workspace for service " - + serviceName - + " check if the mapping exists in service-config.xml or " - + " the the mapped workspace exists in the Nuxeo repository"); - } - RepositoryInstance repoSession = null; + try{ + handler.prepare(Action.GET_ALL); + repoSession = getRepositorySession(); + DocumentRef wsDocRef = new IdRef(nuxeoWspaceId); + DocumentModelList docList = repoSession.getChildren(wsDocRef); + //set reposession to handle the document + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelListWrapper wrapDoc = new DocumentModelListWrapper( + docList); + handler.handle(Action.GET_ALL, wrapDoc); + handler.complete(Action.GET_ALL, wrapDoc); + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } - try { - handler.prepare(Action.GET_ALL); - repoSession = getRepositorySession(); - DocumentRef wsDocRef = new IdRef(nuxeoWspaceId); - DocumentModelList docList = repoSession.getChildren(wsDocRef); + /** + * update given document in the Nuxeo repository + * + * @param ctx service context under which this method is invoked + * @param id + * of the document + * @param handler + * should be used by the caller to provide and transform the + * document + * @throws DocumentException + */ + @Override + public void update(ServiceContext ctx, String id, DocumentHandler handler) + throws BadRequestException, DocumentNotFoundException, + DocumentException { + if(id == null){ + throw new BadRequestException( + "RemoteRepositoryClient.update: id is missing"); + } + if(handler == null){ + throw new IllegalArgumentException( + "RemoteRepositoryClient.update: handler is missing"); + } + RepositoryInstance repoSession = null; + try{ + handler.prepare(Action.UPDATE); + repoSession = getRepositorySession(); + //FIXME, there is a potential privacy violation here, one tenant could + //retrieve doc id of another tenant and could retrieve the document + //PathRef does not seem to come to rescue as expected. Needs more thoughts. + DocumentRef docRef = new IdRef(id); + DocumentModel doc = null; + try{ + doc = repoSession.getDocument(docRef); + }catch(ClientException ce){ + String msg = "Could not find document to update with id=" + id; + logger.error(msg, ce); + throw new DocumentNotFoundException(msg, ce); + } + //set reposession to handle the document + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); + handler.handle(Action.UPDATE, wrapDoc); + repoSession.saveDocument(doc); + repoSession.save(); + handler.complete(Action.UPDATE, wrapDoc); + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } - ((DocumentModelHandler) handler).setRepositorySession(repoSession); - DocumentModelListWrapper wrapDoc = new DocumentModelListWrapper( - docList); - handler.handle(Action.GET_ALL, wrapDoc); + /** + * delete a document from the Nuxeo repository + * @param ctx service context under which this method is invoked + * @param id + * of the document + * @throws DocumentException + */ + @Override + public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException, + DocumentException { - } catch (DocumentException de) { - throw de; - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception ", e); - } - throw new DocumentException(e); - } finally { - if (repoSession != null) { - releaseRepositorySession(repoSession); - } - } - } + if(logger.isDebugEnabled()){ + logger.debug("deleting document with id=" + id); + } + RepositoryInstance repoSession = null; + try{ + repoSession = getRepositorySession(); + //FIXME, there is a potential privacy violation here, one tenant could + //retrieve doc id of another tenant and could retrieve the document + //PathRef does not seem to come to rescue as expected. needs more thoughts. + DocumentRef docRef = new IdRef(id); + try{ + repoSession.removeDocument(docRef); + }catch(ClientException ce){ + String msg = "could not find document to delete with id=" + id; + logger.error(msg, ce); + throw new DocumentNotFoundException(msg, ce); + } + repoSession.save(); + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } - /** - * update given document in the Nuxeo repository - * - * @param id - * of the document - * @param handler - * should be used by the caller to provide and transform the - * document - * @throws DocumentException - */ - @Override - public void update(String id, DocumentHandler handler) - throws BadRequestException, DocumentNotFoundException, - DocumentException { - if (id == null) { - throw new BadRequestException( - "RemoteRepositoryClient.update: id is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "RemoteRepositoryClient.update: handler is missing"); - } - RepositoryInstance repoSession = null; - try { - handler.prepare(Action.UPDATE); - repoSession = getRepositorySession(); - DocumentRef docRef = new IdRef(id); - DocumentModel doc = null; - try { - doc = repoSession.getDocument(docRef); - } catch (ClientException ce) { - String msg = "Could not find document to update with id=" + id; - logger.error(msg, ce); - throw new DocumentNotFoundException(msg, ce); - } - ((DocumentModelHandler) handler).setRepositorySession(repoSession); - DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); - handler.handle(Action.UPDATE, wrapDoc); - repoSession.saveDocument(doc); - repoSession.save(); - } catch (DocumentException de) { - throw de; - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception ", e); - } - throw new DocumentException(e); - } finally { - if (repoSession != null) { - releaseRepositorySession(repoSession); - } - } - } + private RepositoryInstance getRepositorySession() throws Exception { + // FIXME: is it possible to reuse repository session? + // Authentication failures happen while trying to reuse the session + NuxeoClient client = NuxeoConnector.getInstance().getClient(); + RepositoryInstance repoSession = client.openRepository(); + if(logger.isDebugEnabled()){ + logger.debug("getRepository() repository root: " + repoSession.getRootDocument()); + } + return repoSession; + } - /** - * delete a document from the Nuxeo repository - * - * @param id - * of the document - * @throws DocumentException - */ - @Override - public void delete(String id) throws DocumentNotFoundException, - DocumentException { - - if (logger.isDebugEnabled()) { - logger.debug("deleting document with id=" + id); - } - RepositoryInstance repoSession = null; - try { - repoSession = getRepositorySession(); - DocumentRef docRef = new IdRef(id); - try { - repoSession.removeDocument(docRef); - } catch (ClientException ce) { - String msg = "could not find document to delete with id=" + id; - logger.error(msg, ce); - throw new DocumentNotFoundException(msg, ce); - } - repoSession.save(); - } catch (DocumentException de) { - throw de; - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception ", e); - } - throw new DocumentException(e); - } finally { - if (repoSession != null) { - releaseRepositorySession(repoSession); - } - } - } - - private RepositoryInstance getRepositorySession() throws Exception { - // FIXME: is it possible to reuse repository session? - // Authentication failures happen while trying to reuse the session - NuxeoClient client = NuxeoConnector.getInstance().getClient(); - RepositoryInstance repoSession = client.openRepository(); - if (logger.isDebugEnabled()) { - logger.debug("getRepository() repository root: " - + repoSession.getRootDocument()); - } - return repoSession; - } - - private void releaseRepositorySession(RepositoryInstance repoSession) { - try { - NuxeoClient client = NuxeoConnector.getInstance().getClient(); - // release session - client.releaseRepository(repoSession); - } catch (Exception e) { - logger.error("Could not close the repository session", e); - // no need to throw this service specific exception - } - } + private void releaseRepositorySession(RepositoryInstance repoSession) { + try{ + NuxeoClient client = NuxeoConnector.getInstance().getClient(); + // release session + client.releaseRepository(repoSession); + }catch(Exception e){ + logger.error("Could not close the repository session", e); + // no need to throw this service specific exception + } + } } diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java index 9a762fd1d..4ebe43e60 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java @@ -43,8 +43,10 @@ import java.util.List; import java.util.Map; import org.collectionspace.services.common.ServiceConfig; -import org.collectionspace.services.common.ServiceConfig.NuxeoClientConfig; +import org.collectionspace.services.common.RepositoryClientConfigType; import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.config.TenantBindingConfigReader; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.repository.BadRequestException; import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.common.repository.DocumentHandler.Action; @@ -78,20 +80,17 @@ public class RepositoryRESTClient implements RepositoryClient { } @Override - public String create(String serviceName, DocumentHandler handler) throws BadRequestException, DocumentException { - if(serviceName == null){ - throw new IllegalArgumentException("RepositoryRESTClient.create: serviceName is missing"); - } + public String create(ServiceContext ctx, DocumentHandler handler) throws BadRequestException, DocumentException { + if(handler.getDocumentType() == null){ throw new IllegalArgumentException("RepositoryRESTClient.create: docType is missing"); } if(handler == null){ throw new IllegalArgumentException("RepositoryRESTClient.create: handler is missing"); } - ServiceMain smain = ServiceMain.getInstance(); - String nuxeoWspaceId = smain.getWorkspaceId(serviceName); + String nuxeoWspaceId = ctx.getRepositoryWorkspaceId(); if(nuxeoWspaceId == null){ - throw new DocumentNotFoundException("Unable to find workspace for service " + serviceName + + throw new DocumentNotFoundException("Unable to find workspace for service " + ctx.getServiceName() + " check if the mapping exists in service-config.xml or " + " the the mapped workspace exists in the Nuxeo repository"); } @@ -142,6 +141,7 @@ public class RepositoryRESTClient implements RepositoryClient { //Nuxeo does not set 201 SUCCESS_CREATED on successful creation Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); //handle is not needed on create as queryparams have all data + repHandler.complete(Action.CREATE, wrapDoc); return extractId(document); }catch(Exception e){ @@ -154,7 +154,7 @@ public class RepositoryRESTClient implements RepositoryClient { } @Override - public void get(String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { + public void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { if(handler == null){ throw new IllegalArgumentException("RepositoryRESTClient.get: handler is missing"); @@ -183,6 +183,7 @@ public class RepositoryRESTClient implements RepositoryClient { Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); RepresentationWrapper wrapDoc = new RepresentationWrapper(document); repHandler.handle(Action.GET, wrapDoc); + repHandler.complete(Action.GET, wrapDoc); }catch(Exception e){ if(logger.isDebugEnabled()){ logger.debug("Caught exception ", e); @@ -193,17 +194,13 @@ public class RepositoryRESTClient implements RepositoryClient { } @Override - public void getAll(String serviceName, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { - if(serviceName == null){ - throw new IllegalArgumentException("RepositoryRESTClient.getAll: serviceName is missing"); - } + public void getAll(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { if(handler == null){ throw new IllegalArgumentException("RepositoryRESTClient.getAll: handler is missing"); } - ServiceMain smain = ServiceMain.getInstance(); - String nuxeoWspaceId = smain.getWorkspaceId(serviceName); + String nuxeoWspaceId = ctx.getRepositoryWorkspaceId(); if(nuxeoWspaceId == null){ - throw new DocumentNotFoundException("Unable to find workspace for service " + serviceName + + throw new DocumentNotFoundException("Unable to find workspace for service " + ctx.getServiceName() + " check if the mapping exists in service-config.xml or " + " the the mapped workspace exists in the Nuxeo repository"); } @@ -225,6 +222,7 @@ public class RepositoryRESTClient implements RepositoryClient { Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); RepresentationWrapper wrapDoc = new RepresentationWrapper(document); repHandler.handle(Action.GET_ALL, wrapDoc); + repHandler.complete(Action.GET_ALL, wrapDoc); }catch(Exception e){ if(logger.isDebugEnabled()){ logger.debug("Caught exception ", e); @@ -235,7 +233,7 @@ public class RepositoryRESTClient implements RepositoryClient { } @Override - public void update(String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { + public void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { if(handler == null){ throw new IllegalArgumentException("RepositoryRESTClient.update: handler is missing"); } @@ -259,7 +257,7 @@ public class RepositoryRESTClient implements RepositoryClient { repHandler.handle(Action.UPDATE, wrapDoc); Request request = buildRequest(Method.PUT, completeURL); Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); - + repHandler.complete(Action.UPDATE, wrapDoc); }catch(Exception e){ if(logger.isDebugEnabled()){ logger.debug("Caught exception ", e); @@ -270,7 +268,7 @@ public class RepositoryRESTClient implements RepositoryClient { } @Override - public void delete(String id) throws DocumentNotFoundException, DocumentException { + public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException, DocumentException { if(logger.isDebugEnabled()){ logger.debug("deleting document with id=" + id); @@ -379,15 +377,16 @@ public class RepositoryRESTClient implements RepositoryClient { private NuxeoRESTClient getNuxeoRestClient() { if(nuxeoRestClient == null){ ServiceConfig sconfig = ServiceMain.getInstance().getServiceConfig(); - NuxeoClientConfig nxConfig = sconfig.getNuxeoClientConfig(); + //assumption: there is only one client and that also is rest + RepositoryClientConfigType repConfig = sconfig.getRepositoryClient(); String protocol = "http"; - if(nxConfig.getProtocol() != null && !"".equals(nxConfig.getProtocol())){ - protocol = nxConfig.getProtocol(); + if(repConfig.getProtocol() != null && !"".equals(repConfig.getProtocol())){ + protocol = repConfig.getProtocol(); } NuxeoRESTClient tempClient = new NuxeoRESTClient(protocol, - nxConfig.getHost(), "" + nxConfig.getPort()); + repConfig.getHost(), "" + repConfig.getPort()); - tempClient.setBasicAuthentication(nxConfig.getUser(), nxConfig.getPassword()); + tempClient.setBasicAuthentication(repConfig.getUser(), repConfig.getPassword()); nuxeoRestClient = tempClient; diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java index f2d4b0ce6..1bdd44e54 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java @@ -23,16 +23,15 @@ */ package org.collectionspace.services.nuxeo.client.rest; -import org.collectionspace.services.common.repository.DocumentHandler; import org.collectionspace.services.common.repository.DocumentWrapper; -import org.collectionspace.services.common.repository.DocumentException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.collectionspace.services.common.repository.AbstractDocumentHandler; import org.collectionspace.services.nuxeo.client.*; -import org.dom4j.Document; +import org.w3c.dom.Document; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,98 +43,72 @@ import org.slf4j.LoggerFactory; * $LastChangedDate: $ */ public abstract class RepresentationHandler - implements DocumentHandler { + extends AbstractDocumentHandler { private final Logger logger = LoggerFactory.getLogger(RepresentationHandler.class); - private Map properties = new HashMap(); private List pathParams = new ArrayList(); private Map queryParams = new HashMap(); private Document document; private InputStream inputStream = null; - @Override - public abstract void prepare(Action action) throws Exception; - - @Override - public void handle(Action action, DocumentWrapper wrapDoc) throws Exception { - switch(action){ - case CREATE: - handleCreate(wrapDoc); - break; - case UPDATE: - handleUpdate(wrapDoc); - break; - case GET: - handleGet(wrapDoc); - break; - case GET_ALL: - handleGetAll(wrapDoc); - break; - } - } - @Override public void handleCreate(DocumentWrapper wrapDoc) throws Exception { - if(getCommonObject() == null){ - String msg = "Error creating document: Missing input data"; - logger.error(msg); - throw new IllegalStateException(msg); - } - //FIXME set other parts as well - fillCommonObject(getCommonObject(), wrapDoc); + fillAllParts(wrapDoc); } @Override public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { - if(getCommonObject() == null){ - String msg = "Error updating document: Missing input data"; - logger.error(msg); - throw new IllegalStateException(msg); - } - //FIXME set other parts as well - fillCommonObject(getCommonObject(), wrapDoc); + fillAllParts(wrapDoc); } @Override public void handleGet(DocumentWrapper wrapDoc) throws Exception { - setCommonObject(extractCommonObject(wrapDoc)); - - //FIXME retrive other parts as well + extractAllParts(wrapDoc); } @Override public void handleGetAll(DocumentWrapper wrapDoc) throws Exception { - setCommonObjectList(extractCommonObjectList(wrapDoc)); + setCommonPartList(extractCommonPartList(wrapDoc)); } @Override - public abstract T extractCommonObject(DocumentWrapper wrapDoc) throws Exception; + public void extractAllParts(DocumentWrapper wrapDoc) throws Exception { + setCommonPart(extractCommonPart(wrapDoc)); + + //FIXME retrive other parts as well + } @Override - public abstract void fillCommonObject(T obj, DocumentWrapper wrapDoc) throws Exception; + public abstract T extractCommonPart(DocumentWrapper wrapDoc) throws Exception; @Override - public abstract TL extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception; + public void fillAllParts(DocumentWrapper wrapDoc) throws Exception { + if(getCommonPart() == null){ + String msg = "Error creating document: Missing input data"; + logger.error(msg); + throw new IllegalStateException(msg); + } + //FIXME set other parts as well + fillCommonPart(getCommonPart(), wrapDoc); + } @Override - public abstract void fillCommonObjectList(TL obj, DocumentWrapper wrapDoc) throws Exception; + public abstract void fillCommonPart(T obj, DocumentWrapper wrapDoc) throws Exception; @Override - public abstract T getCommonObject(); + public abstract TL extractCommonPartList(DocumentWrapper wrapDoc) throws Exception; @Override - public abstract void setCommonObject(T obj); + public abstract T getCommonPart(); @Override - public abstract TL getCommonObjectList(); + public abstract void setCommonPart(T obj); @Override - public abstract void setCommonObjectList(TL obj); + public abstract TL getCommonPartList(); @Override - public Document getDocument(DocumentWrapper wrapDoc) throws DocumentException { - throw new UnsupportedOperationException("DocumentHandler.getDocument(wrapDoc)"); - } + public abstract void setCommonPartList(TL obj); /** * @return the pathParams @@ -194,20 +167,4 @@ public abstract class RepresentationHandler public void setDocument(Document document) { this.document = document; } - - /** - * @return the properties - */ - @Override - public Map getProperties() { - return properties; - } - - /** - * @param properties the properties to set - */ - @Override - public void setProperties(Map properties) { - this.properties = properties; - } } diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java index bd459d1dd..d27869ea7 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java @@ -104,75 +104,75 @@ public class NuxeoUtils { } return doc; } - -/** - * Gets the document. - * - * @param repoSession the repo session - * @param csid the csid - * - * @return the document - * - * @throws DocumentException the document exception - */ -public static Document getDocument(RepositoryInstance repoSession, String csid) - throws DocumentException { - Document result = null; - - DocumentModel docModel = getDocumentModel(repoSession, csid); - result = getDocument(repoSession, docModel); - - return result; - } - - /** - * Gets the workspace model. - * - * @param repoSession the repo session - * @param workspaceName the workspace name - * - * @return the workspace model - * - * @throws DocumentException the document exception - * @throws IOException Signals that an I/O exception has occurred. - * @throws ClientException the client exception - */ - public static DocumentModel getWorkspaceModel( - RepositoryInstance repoSession, String workspaceName) - throws DocumentException, IOException, ClientException { - DocumentModel result = null; - - String workspaceUUID = ServiceMain.getInstance().getWorkspaceId( - workspaceName); - DocumentRef workspaceRef = new IdRef(workspaceUUID); - result = repoSession.getDocument(workspaceRef); - - return result; - } - - /** - * Gets the document model. - * - * @param repoSession the repo session - * @param csid the csid - * - * @return the document model - * - * @throws DocumentException the document exception - */ - public static DocumentModel getDocumentModel( - RepositoryInstance repoSession, String csid) - throws DocumentException { - DocumentModel result = null; - - try { - DocumentRef documentRef = new IdRef(csid); - result = repoSession.getDocument(documentRef); - } catch (ClientException e) { - e.printStackTrace(); - } - - return result; - } - + + /** + * Gets the document. + * + * @param repoSession the repo session + * @param csid the csid + * + * @return the document + * + * @throws DocumentException the document exception + */ + public static Document getDocument(RepositoryInstance repoSession, String csid) + throws DocumentException { + Document result = null; + + DocumentModel docModel = getDocumentModel(repoSession, csid); + result = getDocument(repoSession, docModel); + + return result; + } + + /** + * Gets the workspace model. + * + * @param repoSession the repo session + * @param workspaceName the workspace name + * + * @return the workspace model + * + * @throws DocumentException the document exception + * @throws IOException Signals that an I/O exception has occurred. + * @throws ClientException the client exception + */ + public static DocumentModel getWorkspaceModel( + RepositoryInstance repoSession, String workspaceName) + throws DocumentException, IOException, ClientException { + DocumentModel result = null; + //FIXME: commented out as this does not work without tenant qualification + String workspaceUUID = null; +// String workspaceUUID = ServiceMain.getInstance().getWorkspaceId( +// workspaceName); + DocumentRef workspaceRef = new IdRef(workspaceUUID); + result = repoSession.getDocument(workspaceRef); + + return result; + } + + /** + * Gets the document model. + * + * @param repoSession the repo session + * @param csid the csid + * + * @return the document model + * + * @throws DocumentException the document exception + */ + public static DocumentModel getDocumentModel( + RepositoryInstance repoSession, String csid) + throws DocumentException { + DocumentModel result = null; + + try{ + DocumentRef documentRef = new IdRef(csid); + result = repoSession.getDocument(documentRef); + }catch(ClientException e){ + e.printStackTrace(); + } + + return result; + } } diff --git a/services/common/src/main/java/org/collectionspace/services/svn-commit.tmp~ b/services/common/src/main/java/org/collectionspace/services/svn-commit.tmp~ new file mode 100644 index 000000000..58b9185a4 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/svn-commit.tmp~ @@ -0,0 +1,4 @@ + +--This line, and those below, will be ignored-- + +M common/repository/RepositoryClient.java diff --git a/services/common/src/main/resources/service-config.xsd b/services/common/src/main/resources/service-config.xsd index 78e85ba0f..ed7d5c5d7 100644 --- a/services/common/src/main/resources/service-config.xsd +++ b/services/common/src/main/resources/service-config.xsd @@ -17,46 +17,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/common/src/main/resources/service.xsd b/services/common/src/main/resources/service.xsd new file mode 100644 index 000000000..9bc6a7d86 --- /dev/null +++ b/services/common/src/main/resources/service.xsd @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/common/src/main/resources/tenant.xsd b/services/common/src/main/resources/tenant.xsd new file mode 100644 index 000000000..070685103 --- /dev/null +++ b/services/common/src/main/resources/tenant.xsd @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/common/src/main/resources/types.xsd b/services/common/src/main/resources/types.xsd new file mode 100644 index 000000000..ab24291c0 --- /dev/null +++ b/services/common/src/main/resources/types.xsd @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/services/common/src/main/svn-commit.tmp~ b/services/common/src/main/svn-commit.tmp~ new file mode 100644 index 000000000..6990c4d59 --- /dev/null +++ b/services/common/src/main/svn-commit.tmp~ @@ -0,0 +1,5 @@ + +--This line, and those below, will be ignored-- + +D resources/common.xsd +A resources/system-response.xsd diff --git a/services/id/jaxb/pom.xml b/services/id/jaxb/pom.xml index c8b1a545a..129a1dc27 100644 --- a/services/id/jaxb/pom.xml +++ b/services/id/jaxb/pom.xml @@ -82,7 +82,6 @@ com.sun.xml.bind jaxb-impl - 2.1.2 diff --git a/services/id/service/pom.xml b/services/id/service/pom.xml index 5c4467197..6347f2640 100644 --- a/services/id/service/pom.xml +++ b/services/id/service/pom.xml @@ -172,7 +172,7 @@ com.thoughtworks.xstream xstream 1.3.2-SNAPSHOT - + diff --git a/services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/OSGI-INF/core-types-contrib.xml b/services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/OSGI-INF/core-types-contrib.xml index 96e156a0f..2fa6e50a6 100644 --- a/services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/OSGI-INF/core-types-contrib.xml +++ b/services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/OSGI-INF/core-types-contrib.xml @@ -1,13 +1,13 @@ - + - + diff --git a/services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/schemas/intake.xsd b/services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/schemas/intakes-common.xsd similarity index 100% rename from services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/schemas/intake.xsd rename to services/intake/3rdparty/nuxeo-platform-cs-intake/src/main/resources/schemas/intakes-common.xsd diff --git a/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeClient.java b/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeClient.java index ec51628ec..9a941c921 100644 --- a/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeClient.java +++ b/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeClient.java @@ -2,12 +2,13 @@ package org.collectionspace.services.client; import javax.ws.rs.core.Response; -import org.collectionspace.services.intake.Intake; -import org.collectionspace.services.intake.IntakeList; +import org.collectionspace.services.intake.IntakesCommonList; import org.jboss.resteasy.client.ProxyFactory; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.spi.ResteasyProviderFactory; /** @@ -51,7 +52,7 @@ public class IntakeClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#getIntake() */ - public ClientResponse readList() { + public ClientResponse readList() { return intakeProxy.readList(); } @@ -60,7 +61,8 @@ public class IntakeClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#getIntake(java.lang.String) */ - public ClientResponse read(String csid) { + + public ClientResponse read(String csid) { return intakeProxy.read(csid); } @@ -69,8 +71,8 @@ public class IntakeClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#createIntake(org.collectionspace.hello.Intake) */ - public ClientResponse create(Intake intake) { - return intakeProxy.create(intake); + public ClientResponse create(MultipartOutput multipart) { + return intakeProxy.create(multipart); } /** @@ -79,8 +81,9 @@ public class IntakeClient extends BaseServiceClient { * @return * @see org.collectionspace.hello.client.IntakeProxy#updateIntake(java.lang.Long, org.collectionspace.hello.Intake) */ - public ClientResponse update(String csid, Intake intake) { - return intakeProxy.update(csid, intake); + public ClientResponse update(String csid, MultipartOutput multipart) { + return intakeProxy.update(csid, multipart); + } /** diff --git a/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeProxy.java b/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeProxy.java index 40baeef75..fdf0e2cf7 100644 --- a/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeProxy.java +++ b/services/intake/client/src/main/java/org/collectionspace/services/client/IntakeProxy.java @@ -10,37 +10,39 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Response; -import org.collectionspace.services.intake.Intake; -import org.collectionspace.services.intake.IntakeList; +import org.collectionspace.services.intake.IntakesCommonList; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; /** * @version $Revision:$ */ @Path("/intakes/") -@Produces({"application/xml"}) -@Consumes({"application/xml"}) +@Produces({"multipart/mixed"}) +@Consumes({"multipart/mixed"}) public interface IntakeProxy { @GET - ClientResponse readList(); + @Produces({"application/xml"}) + ClientResponse readList(); //(C)reate @POST - ClientResponse create(Intake co); + ClientResponse create(MultipartOutput multipart); //(R)ead @GET @Path("/{csid}") - ClientResponse read(@PathParam("csid") String csid); + ClientResponse read(@PathParam("csid") String csid); //(U)pdate @PUT @Path("/{csid}") - ClientResponse update(@PathParam("csid") String csid, Intake co); + ClientResponse update(@PathParam("csid") String csid, MultipartOutput multipart); //(D)elete @DELETE @Path("/{csid}") ClientResponse delete(@PathParam("csid") String csid); -} \ No newline at end of file +} diff --git a/services/intake/client/src/test/java/org/collectionspace/services/client/test/IntakeServiceTest.java b/services/intake/client/src/test/java/org/collectionspace/services/client/test/IntakeServiceTest.java index 28c937a9a..3b069e03d 100644 --- a/services/intake/client/src/test/java/org/collectionspace/services/client/test/IntakeServiceTest.java +++ b/services/intake/client/src/test/java/org/collectionspace/services/client/test/IntakeServiceTest.java @@ -20,28 +20,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.collectionspace.services.client.test; +package org.collectionspace.services.client.test; import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; import org.collectionspace.services.client.IntakeClient; -import org.collectionspace.services.client.test.ServiceRequestType; -import org.collectionspace.services.intake.Intake; -import org.collectionspace.services.intake.IntakeList; +import org.collectionspace.services.intake.IntakesCommon; +import org.collectionspace.services.intake.IntakesCommonList; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; +import org.jboss.resteasy.plugins.providers.multipart.OutputPart; import org.testng.Assert; import org.testng.annotations.Test; /** * IntakeServiceTest, carries out tests against a * deployed and running Intake Service. - * + * * $LastChangedRevision$ * $LastChangedDate$ */ @@ -52,13 +52,10 @@ public class IntakeServiceTest extends AbstractServiceTest { final String SERVICE_PATH_COMPONENT = "intakes"; private String knownResourceId = null; - // --------------------------------------------------------------- // CRUD tests : CREATE tests // --------------------------------------------------------------- - // Success outcomes - @Override @Test public void create() { @@ -70,8 +67,10 @@ public class IntakeServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. String identifier = createIdentifier(); - Intake intake = createIntakeInstance(identifier); - ClientResponse res = client.create(intake); + + MultipartOutput multipart = createIntakeInstance(identifier); + ClientResponse res = client.create(multipart); + int statusCode = res.getStatus(); // Check the status code of the response: does it match @@ -82,12 +81,13 @@ public class IntakeServiceTest extends AbstractServiceTest { // Does it exactly match the expected status code? verbose("create: status = " + statusCode); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - // Store the ID returned from this create operation for - // additional tests below. + // Store the ID returned from this create operation + // for additional tests below. knownResourceId = extractId(res); + verbose("create: knownResourceId=" + knownResourceId); } @Override @@ -99,298 +99,316 @@ public class IntakeServiceTest extends AbstractServiceTest { } // Failure outcomes - // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. - public void createWithEmptyEntityBody() {} - public void createWithMalformedXml() {} - public void createWithWrongXmlSchema() {} + public void createWithEmptyEntityBody() { + } + + public void createWithMalformedXml() { + } + + public void createWithWrongXmlSchema() { + } -/* + /* @Override @Test(dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithEmptyEntityBody() { - - // Perform setup. - setupCreateWithEmptyEntityBody(); - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - String mediaType = MediaType.APPLICATION_XML; - final String entity = ""; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("createWithEmptyEntityBody url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithEmptyEntityBody(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + String mediaType = MediaType.APPLICATION_XML; + final String entity = ""; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("createWithEmptyEntityBody url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithMalformedXml() { - - // Perform setup. - setupCreateWithMalformedXml(); - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - String mediaType = MediaType.APPLICATION_XML; - final String entity = MALFORMED_XML_DATA; // Constant from base class. - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("createWithMalformedXml url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithMalformedXml(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + String mediaType = MediaType.APPLICATION_XML; + final String entity = MALFORMED_XML_DATA; // Constant from base class. + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("createWithMalformedXml url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithWrongXmlSchema() { - - // Perform setup. - setupCreateWithWrongXmlSchema(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - String mediaType = MediaType.APPLICATION_XML; - final String entity = WRONG_XML_SCHEMA_DATA; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("createWithWrongSchema url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } -*/ + // Perform setup. + setupCreateWithWrongXmlSchema(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + String mediaType = MediaType.APPLICATION_XML; + final String entity = WRONG_XML_SCHEMA_DATA; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("createWithWrongSchema url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + */ // --------------------------------------------------------------- // CRUD tests : READ tests // --------------------------------------------------------------- - // Success outcomes - @Override @Test(dependsOnMethods = {"create"}) public void read() { - + // Perform setup. setupRead(); // Submit the request to the service and store the response. - ClientResponse res = client.read(knownResourceId); + ClientResponse res = client.read(knownResourceId); int statusCode = res.getStatus(); - + // Check the status code of the response: does it match // the expected response(s)? verbose("read: status = " + statusCode); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + //FIXME: remove the following try catch once Aron fixes signatures + try{ + MultipartInput input = (MultipartInput) res.getEntity(); + IntakesCommon intake = (IntakesCommon) extractPart(input, + getCommonPartName(), IntakesCommon.class); + Assert.assertNotNull(intake); + }catch(Exception e){ + throw new RuntimeException(e); + } } // Failure outcomes - @Override @Test(dependsOnMethods = {"read"}) public void readNonExistent() { // Perform setup. setupReadNonExistent(); - + // Submit the request to the service and store the response. - ClientResponse res = client.read(NON_EXISTENT_ID); + ClientResponse res = client.read(NON_EXISTENT_ID); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("readNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - // --------------------------------------------------------------- // CRUD tests : READ_LIST tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = {"createList"}) + @Test(dependsOnMethods = {"read"}) public void readList() { - + // Perform setup. setupReadList(); // Submit the request to the service and store the response. - ClientResponse res = client.readList(); - IntakeList list = res.getEntity(); + ClientResponse res = client.readList(); + IntakesCommonList list = res.getEntity(); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("readList: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); // Optionally output additional data about list members for debugging. boolean iterateThroughList = false; - if (iterateThroughList && logger.isDebugEnabled()) { - List items = - list.getIntakeListItem(); + if(iterateThroughList && logger.isDebugEnabled()){ + List items = + list.getIntakeListItem(); int i = 0; - for(IntakeList.IntakeListItem item : items){ + for(IntakesCommonList.IntakeListItem item : items){ verbose("readList: list-item[" + i + "] csid=" + - item.getCsid()); + item.getCsid()); verbose("readList: list-item[" + i + "] objectNumber=" + - item.getEntryNumber()); + item.getEntryNumber()); verbose("readList: list-item[" + i + "] URI=" + - item.getUri()); + item.getUri()); i++; } } - + } // Failure outcomes - // None at present. - - // --------------------------------------------------------------- // CRUD tests : UPDATE tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = {"create"}) + @Test(dependsOnMethods = {"read"}) public void update() { - + // Perform setup. setupUpdate(); - // Retrieve an existing resource that we can update. - ClientResponse res = client.read(knownResourceId); - verbose("read: status = " + res.getStatus()); - Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); - Intake intake = res.getEntity(); - verbose("Got object to update with ID: " + knownResourceId, - intake, Intake.class); - - // Update the content of this resource. - intake.setEntryNumber("updated-" + intake.getEntryNumber()); - intake.setEntryDate("updated-" + intake.getEntryDate()); - - // Submit the request to the service and store the response. - res = client.update(knownResourceId, intake); - int statusCode = res.getStatus(); - Intake updatedObject = res.getEntity(); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("update: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - - // Check the contents of the response: does it match - // what was submitted? - verbose("update: ", updatedObject, Intake.class); - Assert.assertEquals(updatedObject.getEntryDate(), - intake.getEntryDate(), - "Data in updated object did not match submitted data."); + try{ //ideally, just remove try-catch and let the exception bubble up + // Retrieve an existing resource that we can update. + ClientResponse res = + client.read(knownResourceId); + verbose("update: read status = " + res.getStatus()); + Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); + + verbose("got object to update with ID: " + knownResourceId); + MultipartInput input = (MultipartInput) res.getEntity(); + IntakesCommon intake = (IntakesCommon) extractPart(input, + getCommonPartName(), IntakesCommon.class); + Assert.assertNotNull(intake); + + // Update the content of this resource. + // Update the content of this resource. + intake.setEntryNumber("updated-" + intake.getEntryNumber()); + intake.setEntryDate("updated-" + intake.getEntryDate()); + verbose("to be updated object", intake, IntakesCommon.class); + // Submit the request to the service and store the response. + MultipartOutput output = new MultipartOutput(); + OutputPart commonPart = output.addPart(intake, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", getCommonPartName()); + + res = client.update(knownResourceId, output); + int statusCode = res.getStatus(); + // Check the status code of the response: does it match the expected response(s)? + verbose("update: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + + input = (MultipartInput) res.getEntity(); + IntakesCommon updatedIntake = + (IntakesCommon) extractPart(input, + getCommonPartName(), IntakesCommon.class); + Assert.assertNotNull(updatedIntake); + + Assert.assertEquals(updatedIntake.getEntryDate(), + intake.getEntryDate(), + "Data in updated object did not match submitted data."); + }catch(Exception e){ + e.printStackTrace(); + } } // Failure outcomes - // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. - public void updateWithEmptyEntityBody() {} - public void updateWithMalformedXml() {} - public void updateWithWrongXmlSchema() {} + public void updateWithEmptyEntityBody() { + } + + public void updateWithMalformedXml() { + } + + public void updateWithWrongXmlSchema() { + } -/* + /* @Override @Test(dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithEmptyEntityBody() { - - // Perform setup. - setupUpdateWithEmptyEntityBody(); - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - String mediaType = MediaType.APPLICATION_XML; - final String entity = ""; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("updateWithEmptyEntityBody url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithEmptyEntityBody(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + String mediaType = MediaType.APPLICATION_XML; + final String entity = ""; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("updateWithEmptyEntityBody url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithMalformedXml() { - // Perform setup. - setupUpdateWithMalformedXml(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - String mediaType = MediaType.APPLICATION_XML; - final String entity = MALFORMED_XML_DATA; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("updateWithMalformedXml: url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithMalformedXml(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + String mediaType = MediaType.APPLICATION_XML; + final String entity = MALFORMED_XML_DATA; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("updateWithMalformedXml: url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithWrongXmlSchema() { - - // Perform setup. - setupUpdateWithWrongXmlSchema(); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - String mediaType = MediaType.APPLICATION_XML; - final String entity = WRONG_XML_SCHEMA_DATA; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - verbose("updateWithWrongSchema: url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } -*/ + // Perform setup. + setupUpdateWithWrongXmlSchema(); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + String mediaType = MediaType.APPLICATION_XML; + final String entity = WRONG_XML_SCHEMA_DATA; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("updateWithWrongSchema: url=" + url + " status=" + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + */ @Override @Test(dependsOnMethods = {"update", "testSubmitRequest"}) public void updateNonExistent() { @@ -401,28 +419,27 @@ public class IntakeServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. // Note: The ID used in this 'create' call may be arbitrary. // The only relevant ID may be the one used in update(), below. - Intake intake = createIntakeInstance(NON_EXISTENT_ID); - ClientResponse res = - client.update(NON_EXISTENT_ID, intake); + + // The only relevant ID may be the one used in update(), below. + MultipartOutput multipart = createIntakeInstance(NON_EXISTENT_ID); + ClientResponse res = + client.update(NON_EXISTENT_ID, multipart); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? verbose("updateNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } // --------------------------------------------------------------- // CRUD tests : DELETE tests // --------------------------------------------------------------- - // Success outcomes - @Override - @Test(dependsOnMethods = - {"create", "read", "update"}) + @Test(dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"}) public void delete() { // Perform setup. @@ -436,12 +453,11 @@ public class IntakeServiceTest extends AbstractServiceTest { // the expected response(s)? verbose("delete: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } // Failure outcomes - @Override @Test(dependsOnMethods = {"delete"}) public void deleteNonExistent() { @@ -457,15 +473,13 @@ public class IntakeServiceTest extends AbstractServiceTest { // the expected response(s)? verbose("deleteNonExistent: status = " + res.getStatus()); Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - // --------------------------------------------------------------- // Utility tests : tests of code used in tests above // --------------------------------------------------------------- - /** * Tests the code for manually submitting data that is used by several * of the methods above. @@ -480,36 +494,38 @@ public class IntakeServiceTest extends AbstractServiceTest { String method = ServiceRequestType.READ.httpMethodName(); String url = getResourceURL(knownResourceId); int statusCode = submitRequest(method, url); - + // Check the status code of the response: does it match // the expected response(s)? verbose("testSubmitRequest: url=" + url + " status=" + statusCode); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } + } // --------------------------------------------------------------- // Utility methods used by tests above // --------------------------------------------------------------- - @Override public String getServicePathComponent() { return SERVICE_PATH_COMPONENT; } - - private Intake createIntakeInstance(String identifier) { - Intake intake = - createIntakeInstance( + + private MultipartOutput createIntakeInstance(String identifier) { + return createIntakeInstance( "entryNumber-" + identifier, "entryDate-" + identifier); - return intake; } - - private Intake createIntakeInstance(String entryNumber, String entryDate) { - Intake intake = new Intake(); + + private MultipartOutput createIntakeInstance(String entryNumber, String entryDate) { + IntakesCommon intake = new IntakesCommon(); intake.setEntryNumber(entryNumber); intake.setEntryDate(entryDate); - return intake; - } + MultipartOutput multipart = new MultipartOutput(); + OutputPart commonPart = multipart.addPart(intake, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", getCommonPartName()); + + verbose("to be created, intake common ", intake, IntakesCommon.class); + return multipart; + } } diff --git a/services/intake/jaxb/pom.xml b/services/intake/jaxb/pom.xml index d2528a044..8dce3b89c 100644 --- a/services/intake/jaxb/pom.xml +++ b/services/intake/jaxb/pom.xml @@ -56,8 +56,8 @@ com.sun.xml.bind jaxb-impl - 2.1.2 - + 2.1.9 + diff --git a/services/intake/jaxb/src/main/resources/intake.xsd b/services/intake/jaxb/src/main/resources/intakes-common.xsd similarity index 95% rename from services/intake/jaxb/src/main/resources/intake.xsd rename to services/intake/jaxb/src/main/resources/intakes-common.xsd index a65b93c3b..485eafa75 100644 --- a/services/intake/jaxb/src/main/resources/intake.xsd +++ b/services/intake/jaxb/src/main/resources/intakes-common.xsd @@ -1,9 +1,9 @@ @@ -12,7 +12,7 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/services/intake/service/profiles.xml b/services/intake/service/profiles.xml new file mode 100644 index 000000000..347b9df22 --- /dev/null +++ b/services/intake/service/profiles.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeResource.java b/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeResource.java index d7189ccd8..3a1dd56e3 100644 --- a/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeResource.java +++ b/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeResource.java @@ -36,53 +36,62 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; -import org.collectionspace.services.intake.IntakeList.*; +import org.collectionspace.services.common.AbstractCollectionSpaceResource; +import org.collectionspace.services.intake.IntakesCommonList.*; -import org.collectionspace.services.intake.nuxeo.IntakeConstants; import org.collectionspace.services.intake.nuxeo.IntakeHandlerFactory; -import org.collectionspace.services.common.NuxeoClientType; +import org.collectionspace.services.common.ClientType; import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.common.repository.DocumentHandler; -import org.collectionspace.services.common.repository.RepositoryClient; -import org.collectionspace.services.common.repository.RepositoryClientFactory; +import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; +import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.util.HttpResponseCodes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path("/intakes") -@Consumes("application/xml") -@Produces("application/xml") -public class IntakeResource { +@Consumes("multipart/mixed") +@Produces("multipart/mixed") +public class IntakeResource extends AbstractCollectionSpaceResource { - public final static String INTAKE_SERVICE_NAME = "intakes"; + private final static String serviceName = "intakes"; final Logger logger = LoggerFactory.getLogger(IntakeResource.class); //FIXME retrieve client type from configuration - final static NuxeoClientType CLIENT_TYPE = ServiceMain.getInstance().getNuxeoClientType(); + final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); public IntakeResource() { // do nothing } - @POST - public Response createIntake( - Intake intakeObject) { + @Override + public String getServiceName() { + return serviceName; + } - String csid = null; - try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - IntakeHandlerFactory handlerFactory = IntakeHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - handler.setCommonObject(intakeObject); - csid = client.create(INTAKE_SERVICE_NAME, handler); - intakeObject.setCsid(csid); - if(logger.isDebugEnabled()){ - verbose("createIntake: ", intakeObject); + @Override + public DocumentHandler createDocumentHandler(ServiceContext ctx) throws Exception { + DocumentHandler docHandler = IntakeHandlerFactory.getInstance().getHandler( + ctx.getRepositoryClientType().toString()); + docHandler.setServiceContext(ctx); + if(ctx.getInput() != null){ + Object obj = ctx.getInputPart(ctx.getCommonPartLabel(), IntakesCommon.class); + if(obj != null){ + docHandler.setCommonPart((IntakesCommon) obj); } + } + return docHandler; + } + + @POST + public Response createIntake(MultipartInput input) { + try{ + ServiceContext ctx = createServiceContext(input); + DocumentHandler handler = createDocumentHandler(ctx); + String csid = getRepositoryClient(ctx).create(ctx, handler); + //intakeObject.setCsid(csid); UriBuilder path = UriBuilder.fromResource(IntakeResource.class); path.path("" + csid); Response response = Response.created(path.build()).build(); @@ -99,10 +108,10 @@ public class IntakeResource { @GET @Path("{csid}") - public Intake getIntake( + public MultipartOutput getIntake( @PathParam("csid") String csid) { if(logger.isDebugEnabled()){ - verbose("getIntake with csid=" + csid); + logger.debug("getIntake with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("getIntake: missing csid!"); @@ -111,14 +120,12 @@ public class IntakeResource { "text/plain").build(); throw new WebApplicationException(response); } - Intake intakeObject = null; + MultipartOutput result = null; try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - IntakeHandlerFactory handlerFactory = IntakeHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - client.get(csid, handler); - intakeObject = (Intake) handler.getCommonObject(); + ServiceContext ctx = createServiceContext(null); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).get(ctx, csid, handler); + result = ctx.getOutput(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ logger.debug("getIntake", dnfe); @@ -135,29 +142,24 @@ public class IntakeResource { Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build(); throw new WebApplicationException(response); } - - if(intakeObject == null){ + if(result == null){ Response response = Response.status(Response.Status.NOT_FOUND).entity( "Get failed, the requested Intake CSID:" + csid + ": was not found.").type( "text/plain").build(); throw new WebApplicationException(response); } - if(logger.isDebugEnabled()){ - verbose("getIntake: ", intakeObject); - } - return intakeObject; + return result; } @GET - public IntakeList getIntakeList(@Context UriInfo ui) { - IntakeList intakeObjectList = new IntakeList(); + @Produces("application/xml") + public IntakesCommonList getIntakeList(@Context UriInfo ui) { + IntakesCommonList intakeObjectList = new IntakesCommonList(); try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - IntakeHandlerFactory handlerFactory = IntakeHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - client.getAll(INTAKE_SERVICE_NAME, handler); - intakeObjectList = (IntakeList) handler.getCommonObjectList(); + ServiceContext ctx = createServiceContext(null); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).getAll(ctx, handler); + intakeObjectList = (IntakesCommonList) handler.getCommonPartList(); }catch(Exception e){ if(logger.isDebugEnabled()){ logger.debug("Caught exception in getIntakeList", e); @@ -171,11 +173,11 @@ public class IntakeResource { @PUT @Path("{csid}") - public Intake updateIntake( + public MultipartOutput updateIntake( @PathParam("csid") String csid, - Intake theUpdate) { + MultipartInput theUpdate) { if(logger.isDebugEnabled()){ - verbose("updateIntake with csid=" + csid); + logger.debug("updateIntake with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("updateIntake: missing csid!"); @@ -184,16 +186,12 @@ public class IntakeResource { "text/plain").build(); throw new WebApplicationException(response); } - if(logger.isDebugEnabled()){ - verbose("updateIntake with input: ", theUpdate); - } + MultipartOutput result = null; try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - IntakeHandlerFactory handlerFactory = IntakeHandlerFactory.getInstance(); - DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); - handler.setCommonObject(theUpdate); - client.update(csid, handler); + ServiceContext ctx = createServiceContext(theUpdate); + DocumentHandler handler = createDocumentHandler(ctx); + getRepositoryClient(ctx).update(ctx, csid, handler); + result = ctx.getOutput(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ logger.debug("caugth exception in updateIntake", dnfe); @@ -207,7 +205,7 @@ public class IntakeResource { Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build(); throw new WebApplicationException(response); } - return theUpdate; + return result; } @DELETE @@ -215,7 +213,7 @@ public class IntakeResource { public Response deleteIntake(@PathParam("csid") String csid) { if(logger.isDebugEnabled()){ - verbose("deleteIntake with csid=" + csid); + logger.debug("deleteIntake with csid=" + csid); } if(csid == null || "".equals(csid)){ logger.error("deleteIntake: missing csid!"); @@ -225,9 +223,8 @@ public class IntakeResource { throw new WebApplicationException(response); } try{ - RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); - RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); - client.delete(csid); + ServiceContext ctx = createServiceContext(null); + getRepositoryClient(ctx).delete(ctx, csid); return Response.status(HttpResponseCodes.SC_OK).build(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ @@ -244,23 +241,4 @@ public class IntakeResource { } } - - private void verbose(String msg, Intake intakeObject) { - try{ - verbose(msg); - JAXBContext jc = JAXBContext.newInstance( - Intake.class); - - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - m.marshal(intakeObject, System.out); - }catch(Exception e){ - e.printStackTrace(); - } - - } - - private void verbose(String msg) { - System.out.println("IntakeResource. " + msg); - } } diff --git a/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeService.java b/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeService.java deleted file mode 100644 index f74ff484a..000000000 --- a/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeService.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * - */ -package org.collectionspace.services.intake; - -import java.io.IOException; -import org.dom4j.Document; -import org.dom4j.DocumentException; - -import org.collectionspace.services.intake.Intake; - -/** - * @author remillet - * - */ -public interface IntakeService { - - public final static String INTAKE_SCHEMA_NAME = "intake"; - - // Create - Document postIntake(Intake co) - throws DocumentException, IOException; - - // Read single object - Document getIntake(String csid) throws DocumentException, - IOException; - - // Read a list of objects - Document getIntakeList() throws DocumentException, IOException; - - // Update - Document putIntake(String csid, Intake theUpdate) - throws DocumentException, IOException; - - // Delete - Document deleteIntake(String csid) throws DocumentException, - IOException; -} diff --git a/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeServiceNuxeoImpl.java b/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeServiceNuxeoImpl.java deleted file mode 100644 index 003432699..000000000 --- a/services/intake/service/src/main/java/org/collectionspace/services/intake/IntakeServiceNuxeoImpl.java +++ /dev/null @@ -1,215 +0,0 @@ -/** - * - */ -package org.collectionspace.services.intake; - -import org.collectionspace.services.*; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.collectionspace.services.nuxeo.client.rest.NuxeoRESTClient; -import org.collectionspace.services.nuxeo.CollectionSpaceServiceNuxeoImpl; -import org.collectionspace.services.intake.Intake; -import org.collectionspace.services.IntakeJAXBSchema; - -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.io.SAXReader; -import org.restlet.resource.Representation; - -/** - * @author remillet - * - */ -public class IntakeServiceNuxeoImpl extends - CollectionSpaceServiceNuxeoImpl implements IntakeService { - - final static String INTAKE_NUXEO_DOCTYPE = "Intake"; - final static String INTAKE_NUXEO_SCHEMA_NAME = "intake"; - final static String INTAKE_NUXEO_DC_TITLE = "CollectionSpace-Intake"; - - // replace WORKSPACE_UID for resource workspace - static String CS_INTAKE_WORKSPACE_UID = "c04210c4-9426-475f-b4ee-aa3d6aa4b97c"; - - public Document deleteIntake(String csid) - throws DocumentException, IOException { - - Document result = null; - -// NuxeoRESTClient nxClient = getClient(); -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// -// pathParams.add("default"); -// pathParams.add(csid); -// pathParams.add("deleteDocumentRestlet"); -// Representation res = nxClient.get(pathParams, queryParams); -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - public Document getIntake(String csid) throws DocumentException, - IOException { - Document result = null; - -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// -// pathParams.add("default"); -// pathParams.add(csid); -// pathParams.add("export"); -// queryParams.put("format", "XML"); -// -// NuxeoRESTClient nxClient = getClient(); -// Representation res = nxClient.get(pathParams, queryParams); -// -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - public Document getIntakeList() throws DocumentException, - IOException { - Document result = null; - -// NuxeoRESTClient nxClient = getClient(); -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// pathParams = Arrays.asList("default", -// CS_INTAKE_WORKSPACE_UID, "browse"); -// Representation res = nxClient.get(pathParams, queryParams); -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - public Document postIntake(Intake co) - throws DocumentException, IOException { - Document result = null; - -// NuxeoRESTClient nxClient = getClient(); -// -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// pathParams.add("default"); -// pathParams.add(CS_INTAKE_WORKSPACE_UID); -// pathParams.add("createDocument"); -// queryParams.put("docType", INTAKE_NUXEO_DOCTYPE); -// -// // a default title for the Dublin Core schema -// queryParams.put("dublincore:title", INTAKE_NUXEO_DC_TITLE); -// -// // Intake core values -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.CURRENT_OWNER, co -// .getCurrentOwner()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.DEPOSITOR, co.getDepositor()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.DEPOSITORS_REQUIREMENTS, co -// .getDepositorsRequirements()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_DATE, co.getEntryDate()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_METHOD, co -// .getEntryMethod()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_NOTE, co.getEntryNote()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_NUMBER, co -// .getEntryNumber()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_REASON, co.getEntryReason()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.PACKING_NOTE, co.getPackingNote()); -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.RETURN_DATE, co.getReturnDate()); -// -// ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]); -// Representation res = nxClient.post(pathParams, queryParams, bais); -// -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - - public Document putIntake(String csid, Intake theUpdate) - throws DocumentException, IOException { - Document result = null; - -// List pathParams = new ArrayList(); -// Map queryParams = new HashMap(); -// pathParams.add("default"); -// pathParams.add(csid); -// pathParams.add("updateDocumentRestlet"); -// -// // todo: intelligent merge needed -// if (theUpdate.getCurrentOwner() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.CURRENT_OWNER, theUpdate.getCurrentOwner()); -// } -// -// if (theUpdate.getDepositor() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.DEPOSITOR, theUpdate.getDepositor()); -// } -// -// if (theUpdate.getDepositorsRequirements() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.DEPOSITORS_REQUIREMENTS, theUpdate.getDepositorsRequirements()); -// } -// -// if (theUpdate.getEntryDate() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_DATE, theUpdate.getEntryDate()); -// } -// -// if (theUpdate.getEntryMethod() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_METHOD, theUpdate.getEntryMethod()); -// } -// -// if (theUpdate.getEntryNote() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_NOTE, theUpdate.getEntryNote()); -// } -// -// if (theUpdate.getEntryNumber() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_NUMBER, theUpdate.getEntryNumber()); -// } -// -// if (theUpdate.getEntryReason() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.ENTRY_REASON, theUpdate.getEntryReason()); -// } -// -// if (theUpdate.getPackingNote() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.PACKING_NOTE, theUpdate.getPackingNote()); -// } -// -// if (theUpdate.getReturnDate() != null) { -// queryParams.put(INTAKE_NUXEO_SCHEMA_NAME + ":" -// + IntakeJAXBSchema.RETURN_DATE, theUpdate.getReturnDate()); -// } -// -// NuxeoRESTClient nxClient = getClient(); -// Representation res = nxClient.get(pathParams, queryParams); -// SAXReader reader = new SAXReader(); -// result = reader.read(res.getStream()); - - return result; - } - -} diff --git a/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeDocumentModelHandler.java b/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeDocumentModelHandler.java index 0d0c55355..71f44b007 100644 --- a/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeDocumentModelHandler.java +++ b/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeDocumentModelHandler.java @@ -28,11 +28,10 @@ import java.util.List; import org.collectionspace.services.IntakeJAXBSchema; import org.collectionspace.services.common.repository.DocumentWrapper; -import org.collectionspace.services.intake.Intake; -import org.collectionspace.services.intake.IntakeList; -import org.collectionspace.services.intake.IntakeList.IntakeListItem; +import org.collectionspace.services.intake.IntakesCommon; +import org.collectionspace.services.intake.IntakesCommonList; +import org.collectionspace.services.intake.IntakesCommonList.IntakeListItem; import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler; -import org.collectionspace.services.intake.nuxeo.IntakeConstants; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; @@ -46,19 +45,19 @@ import org.slf4j.LoggerFactory; * $LastChangedDate: $ */ public class IntakeDocumentModelHandler - extends DocumentModelHandler { + extends DocumentModelHandler { private final Logger logger = LoggerFactory.getLogger(IntakeDocumentModelHandler.class); /** * intake is used to stash JAXB object to use when handle is called * for Action.CREATE, Action.UPDATE or Action.GET */ - private Intake intake; + private IntakesCommon intake; /** * intakeList is stashed when handle is called * for ACTION.GET_ALL */ - private IntakeList intakeList; + private IntakesCommonList intakeList; @Override public void prepare(Action action) throws Exception { @@ -66,148 +65,54 @@ public class IntakeDocumentModelHandler } /** - * getCommonObject get associated intake + * getCommonPart get associated intake * @return */ @Override - public Intake getCommonObject() { + public IntakesCommon getCommonPart() { return intake; } /** - * setCommonObject set associated intake + * setCommonPart set associated intake * @param intake */ @Override - public void setCommonObject(Intake intake) { + public void setCommonPart(IntakesCommon intake) { this.intake = intake; } /** - * getIntakeList get associated intake (for index/GET_ALL) + * getCommonPartList get associated intake (for index/GET_ALL) * @return */ @Override - public IntakeList getCommonObjectList() { + public IntakesCommonList getCommonPartList() { return intakeList; } @Override - public void setCommonObjectList(IntakeList intakeList) { + public void setCommonPartList(IntakesCommonList intakeList) { this.intakeList = intakeList; } @Override - public Intake extractCommonObject(DocumentWrapper wrapDoc) + public IntakesCommon extractCommonPart(DocumentWrapper wrapDoc) throws Exception { - DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); - Intake intakeObject = new Intake(); - - //FIXME property get should be dynamically set using schema inspection - //so it does not require hard coding - - // intake core values - intakeObject.setCurrentOwner((String)docModel.getPropertyValue( - getQProperty(IntakeJAXBSchema.CURRENT_OWNER))); - - intakeObject.setDepositor((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.DEPOSITOR))); - - intakeObject.setDepositorsRequirements((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.DEPOSITORS_REQUIREMENTS))); - - intakeObject.setEntryDate((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_DATE))); - - intakeObject.setEntryMethod((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_METHOD))); - - intakeObject.setEntryNote((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_NOTE))); - - intakeObject.setEntryNumber((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_NUMBER))); - - intakeObject.setEntryReason((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_REASON))); - - intakeObject.setPackingNote((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.PACKING_NOTE))); - - intakeObject.setReturnDate((String)docModel.getPropertyValue(getQProperty( - IntakeJAXBSchema.RETURN_DATE))); - - return intakeObject; + throw new UnsupportedOperationException(); } @Override - public void fillCommonObject(Intake intakeObject, DocumentWrapper wrapDoc) throws Exception { - DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); - //FIXME property setter should be dynamically set using schema inspection - //so it does not require hard coding - - // a default title for the Dublin Core schema - docModel.setPropertyValue("dublincore:title", IntakeConstants.NUXEO_DC_TITLE); - - // intake core values - if(intakeObject.getCurrentOwner() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.CURRENT_OWNER), intakeObject.getCurrentOwner()); - } - - if(intakeObject.getDepositor() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.DEPOSITOR), intakeObject.getDepositor()); - } - - if(intakeObject.getDepositorsRequirements() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.DEPOSITORS_REQUIREMENTS), intakeObject.getDepositorsRequirements()); - } - - if(intakeObject.getEntryDate() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_DATE), intakeObject.getEntryDate()); - } - - if(intakeObject.getEntryMethod() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_METHOD), intakeObject.getEntryMethod()); - } - - if(intakeObject.getEntryNote() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_NOTE), intakeObject.getEntryNote()); - } - - if(intakeObject.getEntryNumber() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_NUMBER), intakeObject.getEntryNumber()); - } - - if(intakeObject.getEntryReason() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.ENTRY_REASON), intakeObject.getEntryReason()); - } - - if(intakeObject.getPackingNote() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.PACKING_NOTE), intakeObject.getPackingNote()); - } - - if(intakeObject.getReturnDate() != null){ - docModel.setPropertyValue(getQProperty( - IntakeJAXBSchema.RETURN_DATE), intakeObject.getReturnDate()); - } - + public void fillCommonPart(IntakesCommon intakeObject, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException(); } @Override - public IntakeList extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception { + public IntakesCommonList extractCommonPartList(DocumentWrapper wrapDoc) throws Exception { DocumentModelList docList = (DocumentModelList) wrapDoc.getWrappedObject(); - IntakeList coList = new IntakeList(); - List list = coList.getIntakeListItem(); + IntakesCommonList coList = new IntakesCommonList(); + List list = coList.getIntakeListItem(); //FIXME: iterating over a long list of documents is not a long term //strategy...need to change to more efficient iterating in future @@ -215,11 +120,10 @@ public class IntakeDocumentModelHandler while(iter.hasNext()){ DocumentModel docModel = iter.next(); IntakeListItem ilistItem = new IntakeListItem(); - ilistItem.setEntryNumber((String)docModel.getPropertyValue( - getQProperty(IntakeJAXBSchema.ENTRY_NUMBER))); - //need fully qualified context for URI + ilistItem.setEntryNumber((String) docModel.getProperty(getServiceContext().getCommonPartLabel(), + IntakeJAXBSchema.ENTRY_NUMBER)); String id = docModel.getId(); - ilistItem.setUri("/intakes/" + id); + ilistItem.setUri(getServiceContextPath() + id); ilistItem.setCsid(id); list.add(ilistItem); } @@ -227,24 +131,22 @@ public class IntakeDocumentModelHandler return coList; } - @Override - public void fillCommonObjectList(IntakeList obj, DocumentWrapper wrapDoc) throws Exception { - throw new UnsupportedOperationException(); - } /* (non-Javadoc) * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#getDocumentType() */ + @Override public String getDocumentType() { - return IntakeConstants.NUXEO_DOCTYPE; + return IntakeConstants.NUXEO_DOCTYPE; } - + /** * getQProperty converts the given property to qualified schema property * @param prop * @return */ - private String getQProperty(String prop) { + @Override + public String getQProperty(String prop) { return IntakeConstants.NUXEO_SCHEMA_NAME + ":" + prop; } } diff --git a/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeHandlerFactory.java b/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeHandlerFactory.java index d5f07828e..aaa4374e1 100644 --- a/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeHandlerFactory.java +++ b/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeHandlerFactory.java @@ -23,7 +23,7 @@ */ package org.collectionspace.services.intake.nuxeo; -import org.collectionspace.services.common.NuxeoClientType; +import org.collectionspace.services.common.ClientType; import org.collectionspace.services.common.repository.DocumentHandler; /** @@ -45,9 +45,9 @@ public class IntakeHandlerFactory { } public DocumentHandler getHandler(String clientType) { - if(NuxeoClientType.JAVA.toString().equals(clientType)){ + if(ClientType.JAVA.toString().equals(clientType)){ return new IntakeDocumentModelHandler(); - } else if(NuxeoClientType.REST.toString().equals(clientType)) { + } else if(ClientType.REST.toString().equals(clientType)) { return new IntakeRepresenationHandler(); } throw new IllegalArgumentException("Not supported client=" + clientType); diff --git a/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeRepresenationHandler.java b/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeRepresenationHandler.java index 1723126f6..628114c52 100644 --- a/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeRepresenationHandler.java +++ b/services/intake/service/src/main/java/org/collectionspace/services/intake/nuxeo/IntakeRepresenationHandler.java @@ -29,9 +29,9 @@ import java.util.Map; import org.collectionspace.services.IntakeJAXBSchema; import org.collectionspace.services.common.repository.DocumentWrapper; -import org.collectionspace.services.intake.Intake; -import org.collectionspace.services.intake.IntakeList; -import org.collectionspace.services.intake.IntakeList.IntakeListItem; +import org.collectionspace.services.intake.IntakesCommon; +import org.collectionspace.services.intake.IntakesCommonList; +import org.collectionspace.services.intake.IntakesCommonList.IntakeListItem; import org.collectionspace.services.nuxeo.client.rest.RepresentationHandler; import org.dom4j.Document; import org.dom4j.Element; @@ -45,19 +45,19 @@ import org.slf4j.LoggerFactory; * $LastChangedDate: $ */ public class IntakeRepresenationHandler - extends RepresentationHandler { + extends RepresentationHandler { private final Logger logger = LoggerFactory.getLogger(IntakeRepresenationHandler.class); /** * intakeObj is used to stash JAXB object to use when handle is called * for Action.CREATE, Action.UPDATE or Action.GET */ - private Intake intake; + private IntakesCommon intake; /** * intakeListObject is stashed when handle is called * for ACTION.GET_ALL */ - private IntakeList intakeList; + private IntakesCommonList intakeList; @Override public void prepare(Action action) throws Exception { @@ -70,7 +70,7 @@ public class IntakeRepresenationHandler private void prepare() { Map queryParams = getQueryParams(); - Intake intakeObject = getCommonObject(); + IntakesCommon intakeObject = getCommonPart(); if(intakeObject.getCurrentOwner() != null){ queryParams.put(IntakeConstants.NUXEO_SCHEMA_NAME + ":" + IntakeJAXBSchema.CURRENT_OWNER, intakeObject.getCurrentOwner()); @@ -123,10 +123,10 @@ public class IntakeRepresenationHandler } @Override - public Intake extractCommonObject(DocumentWrapper wrapDoc) + public IntakesCommon extractCommonPart(DocumentWrapper wrapDoc) throws Exception { Document document = (Document) wrapDoc.getWrappedObject(); - Intake intakeObj = new Intake(); + IntakesCommon intakeObj = new IntakesCommon(); //FIXME property get should be dynamically set using schema inspection //so it does not require hard coding @@ -191,19 +191,19 @@ public class IntakeRepresenationHandler } @Override - public void fillCommonObject(Intake co, DocumentWrapper wrapDoc) + public void fillCommonPart(IntakesCommon co, DocumentWrapper wrapDoc) throws Exception { //Nuxeo REST takes create/update through queryParams, nothing to do here } @Override - public IntakeList extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception { + public IntakesCommonList extractCommonPartList(DocumentWrapper wrapDoc) throws Exception { Document document = (Document) wrapDoc.getWrappedObject(); if(logger.isDebugEnabled()){ logger.debug(document.asXML()); } - IntakeList intakeListObject = new IntakeList(); - List list = intakeListObject.getIntakeListItem(); + IntakesCommonList intakeListObject = new IntakesCommonList(); + List list = intakeListObject.getIntakeListItem(); Element root = document.getRootElement(); for(Iterator i = root.elementIterator(); i.hasNext();){ @@ -222,45 +222,42 @@ public class IntakeRepresenationHandler return intakeListObject; } - @Override - public void fillCommonObjectList(IntakeList obj, DocumentWrapper wrapDoc) - throws Exception { - throw new UnsupportedOperationException(); - } @Override - public Intake getCommonObject() { + public IntakesCommon getCommonPart() { return intake; } @Override - public void setCommonObject(Intake obj) { + public void setCommonPart(IntakesCommon obj) { this.intake = obj; } @Override - public IntakeList getCommonObjectList() { + public IntakesCommonList getCommonPartList() { return intakeList; } @Override - public void setCommonObjectList(IntakeList obj) { + public void setCommonPartList(IntakesCommonList obj) { this.intakeList = obj; } /* (non-Javadoc) * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#getDocumentType() */ + @Override public String getDocumentType() { - return IntakeConstants.NUXEO_DOCTYPE; + return IntakeConstants.NUXEO_DOCTYPE; } - + /** * getQProperty converts the given property to qualified schema property * @param prop * @return */ - private String getQProperty(String prop) { + @Override + public String getQProperty(String prop) { return IntakeConstants.NUXEO_SCHEMA_NAME + ":" + prop; } } diff --git a/services/pom.xml b/services/pom.xml index 14f912774..ec406fe07 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -18,8 +18,8 @@ common authentication - relation - query + + acquisition vocabulary id @@ -27,8 +27,8 @@ intake JaxRsServiceProvider client - sdk - IntegrationTests + + @@ -148,7 +148,7 @@ org.jboss.resteasy jaxrs-api - 1.0.2.GA + 1.1.GA net.java.dev.jaxb2-commons @@ -168,7 +168,7 @@ org.jboss.resteasy resteasy-jaxrs - 1.0.2.GA + 1.1.GA commons-httpclient @@ -178,7 +178,7 @@ com.sun.xml.bind jaxb-impl - 2.1.7 + 2.1.9 org.slf4j diff --git a/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java b/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java index 2ec1700ec..4dfc50536 100644 --- a/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java +++ b/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java @@ -16,7 +16,7 @@ * http://www.collectionspace.org * http://wiki.collectionspace.org * - * Copyright © 2009 {Contributing Institution} + * Copyright � 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. @@ -44,45 +44,45 @@ import javax.ws.rs.core.UriInfo; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; -import org.collectionspace.services.relation.RelationList.RelationListItem; -import org.collectionspace.services.common.CollectionSpaceResource; -import org.collectionspace.services.relation.nuxeo.RelationNuxeoConstants; -import org.collectionspace.services.relation.nuxeo.RelationHandlerFactory; -import org.collectionspace.services.common.CollectionSpaceHandlerFactory; +import org.collectionspace.services.common.AbstractCollectionSpaceResource; import org.collectionspace.services.common.NuxeoClientType; -import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.relation.RelationsManager; import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.common.repository.DocumentHandler; -import org.collectionspace.services.common.repository.RepositoryClient; -import org.collectionspace.services.common.repository.RepositoryClientFactory; import org.jboss.resteasy.util.HttpResponseCodes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path("/relations") -@Consumes("application/xml") -@Produces("application/xml") -public class NewRelationResource extends CollectionSpaceResource { +@Consumes("multipart/mixed") +@Produces("multipart/mixed") +public class NewRelationResource extends AbstractCollectionSpaceResource { - public final static String SERVICE_NAME = "relations"; + public final static String serviceName = "relations"; final Logger logger = LoggerFactory.getLogger(NewRelationResource.class); - // FIXME retrieve client type from configuration -// final static NuxeoClientType CLIENT_TYPE = ServiceMain.getInstance() -// .getNuxeoClientType(); - protected String getClientType() { - return ServiceMain.getInstance().getNuxeoClientType().toString(); - } - - protected RepositoryClientFactory getDefaultClientFactory() { - return RepositoryClientFactory.getInstance(); - } - - protected CollectionSpaceHandlerFactory getDefaultHandlerFactory() { - return RelationHandlerFactory.getInstance(); - } + + @Override + public String getServiceName() { + return serviceName; + } + + @Override + public DocumentHandler createDocumentHandler(ServiceContext ctx) throws Exception { + DocumentHandler docHandler = RelationHandlerFactory.getInstance().getHandler( + ctx.getRepositoryClientType().toString()); + docHandler.setServiceContext(ctx); + if(ctx.getInput() != null){ + Object obj = ctx.getInputPart(ctx.getCommonPartLabel(), CollectionobjectsCommon.class); + if(obj != null){ + docHandler.setCommonPart((CollectionobjectsCommon) obj); + } + } + return docHandler; + } + // public NewRelationResource() { // } diff --git a/services/sdk/sample/src/main/java/org/collectionspace/services/sdk/sample/Sample.java b/services/sdk/sample/src/main/java/org/collectionspace/services/sdk/sample/Sample.java index 2b7551eb9..4e1605404 100644 --- a/services/sdk/sample/src/main/java/org/collectionspace/services/sdk/sample/Sample.java +++ b/services/sdk/sample/src/main/java/org/collectionspace/services/sdk/sample/Sample.java @@ -11,8 +11,8 @@ import org.testng.Assert; import org.jboss.resteasy.client.ClientResponse; import org.collectionspace.services.client.CollectionObjectClient; -import org.collectionspace.services.collectionobject.CollectionObject; -import org.collectionspace.services.collectionobject.CollectionObjectList; +import org.collectionspace.services.collectionobject.CollectionobjectsCommon; +import org.collectionspace.services.collectionobject.CollectionobjectsCommonList; public class Sample { @@ -25,15 +25,15 @@ public class Sample { String csid = createCollectionObject(); System.out.println("Created a new collection object with CSID=" + csid); - CollectionObject co = readCollectionObject(csid); + CollectionobjectsCommon co = readCollectionObject(csid); System.out.println("Got a collection object with CSID=" + csid); } static String createCollectionObject() { String result = null; - CollectionObject co = new CollectionObject(); - co.setObjectName("Keiko CollectionObject"); + CollectionobjectsCommon co = new CollectionobjectsCommon(); + co.setObjectName("Keiko CollectionobjectsCommon"); ClientResponse response = collectionObjectClient.create(co); Assert.assertEquals(response.getStatus(), Response.Status.CREATED.getStatusCode()); @@ -42,10 +42,10 @@ public class Sample { return result; } - static CollectionObject readCollectionObject(String csid) { - CollectionObject result = null; + static CollectionobjectsCommon readCollectionObject(String csid) { + CollectionobjectsCommon result = null; - ClientResponse response = collectionObjectClient.read(csid); + ClientResponse response = collectionObjectClient.read(csid); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); result = response.getEntity(); -- 2.47.3