From 758499af3bdce79c0c80ab6392191f8bbe908dd0 Mon Sep 17 00:00:00 2001 From: Ray Lee Date: Fri, 19 Jun 2020 11:22:18 -0400 Subject: [PATCH] DRYD-879: Implement export service. --- services/JaxRsServiceProvider/pom.xml | 7 +- .../CollectionSpaceJaxRsApplication.java | 2 + .../common/vocabulary/AuthorityResource.java | 25 +- .../tenants/tenant-bindings-proto-unified.xml | 38 ++ .../services/common/invocable/Invocable.java | 17 +- services/export/build.xml | 108 +++++ services/export/client/pom.xml | 83 ++++ .../services/client/ExportClient.java | 67 ++++ .../services/client/ExportProxy.java | 48 +++ services/export/jaxb/.gitignore | 3 + services/export/jaxb/pom.xml | 33 ++ .../services/ExportJAXBSchema.java | 9 + .../src/main/resources/exports-common.xsd | 36 ++ services/export/pom.xml | 25 ++ services/export/service/pom.xml | 122 ++++++ .../AbstractDocumentsByQueryIterator.java | 244 ++++++++++++ .../services/export/AbstractExportWriter.java | 57 +++ .../services/export/CsvExportWriter.java | 209 ++++++++++ .../export/DocumentsByCsidIterator.java | 68 ++++ .../export/DocumentsByGroupIterator.java | 40 ++ .../services/export/ExportResource.java | 371 ++++++++++++++++++ .../services/export/ExportWriter.java | 23 ++ .../RelationObjectsByQueryIterator.java | 61 +++ .../export/RelationsByQueryIterator.java | 34 ++ .../StandardDocumentsByQueryIterator.java | 40 ++ .../services/export/XmlExportWriter.java | 63 +++ .../export/nuxeo/ExportConstants.java | 31 ++ .../nuxeo/ExportDocumentModelHandler.java | 249 ++++++++++++ .../export/nuxeo/ExportValidatorHandler.java | 18 + .../src/main/resources/invocationContext.xsd | 36 +- services/pom.xml | 1 + 31 files changed, 2153 insertions(+), 15 deletions(-) create mode 100644 services/export/build.xml create mode 100644 services/export/client/pom.xml create mode 100644 services/export/client/src/main/java/org/collectionspace/services/client/ExportClient.java create mode 100644 services/export/client/src/main/java/org/collectionspace/services/client/ExportProxy.java create mode 100644 services/export/jaxb/.gitignore create mode 100644 services/export/jaxb/pom.xml create mode 100644 services/export/jaxb/src/main/java/org/collectionspace/services/ExportJAXBSchema.java create mode 100644 services/export/jaxb/src/main/resources/exports-common.xsd create mode 100644 services/export/pom.xml create mode 100644 services/export/service/pom.xml create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/AbstractDocumentsByQueryIterator.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/AbstractExportWriter.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/CsvExportWriter.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByCsidIterator.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByGroupIterator.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/ExportResource.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/ExportWriter.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/RelationObjectsByQueryIterator.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/RelationsByQueryIterator.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/StandardDocumentsByQueryIterator.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/XmlExportWriter.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportConstants.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportDocumentModelHandler.java create mode 100644 services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportValidatorHandler.java diff --git a/services/JaxRsServiceProvider/pom.xml b/services/JaxRsServiceProvider/pom.xml index 5a891e309..0b7fc1da6 100644 --- a/services/JaxRsServiceProvider/pom.xml +++ b/services/JaxRsServiceProvider/pom.xml @@ -246,7 +246,12 @@ org.collectionspace.services org.collectionspace.services.imports.service - ${project.version} + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.export.service + ${project.version} org.collectionspace.services 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 842f17a3d..e675a2f75 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 @@ -38,6 +38,7 @@ import org.collectionspace.services.valuationcontrol.ValuationcontrolResource; import org.collectionspace.services.objectexit.ObjectExitResource; import org.collectionspace.services.batch.BatchResource; import org.collectionspace.services.imports.ImportsResource; +import org.collectionspace.services.export.ExportResource; import org.collectionspace.services.location.LocationAuthorityResource; import org.collectionspace.services.place.PlaceAuthorityResource; import org.collectionspace.services.work.WorkAuthorityResource; @@ -111,6 +112,7 @@ public class CollectionSpaceJaxRsApplication extends Application singletons.add(new PermissionResource()); singletons.add(new ServiceGroupResource()); singletons.add(new ImportsResource()); + singletons.add(new ExportResource()); singletons.add(new StructuredDateResource()); singletons.add(new SystemInfoResource()); singletons.add(new IndexResource()); diff --git a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java index d3c47014b..3709bb244 100644 --- a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java +++ b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java @@ -49,6 +49,7 @@ import org.collectionspace.services.client.PoxPayloadIn; import org.collectionspace.services.client.PoxPayloadOut; import org.collectionspace.services.client.XmlTools; import org.collectionspace.services.client.workflow.WorkflowClient; +import org.collectionspace.services.common.CollectionSpaceResource; import org.collectionspace.services.common.CSWebApplicationException; import org.collectionspace.services.common.NuxeoBasedResource; import org.collectionspace.services.common.ResourceMap; @@ -777,7 +778,7 @@ public abstract class AuthorityResource ) throws Exception { return updateAuthorityItem(null, itemServiceCtx, resourceMap, uriInfo, parentspecifier, itemspecifier, theUpdate, shouldUpdateRevNumber, isProposed, isSASItem); } - + public PoxPayloadOut updateAuthorityItem( ServiceContext parentCtx, ServiceContext itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls @@ -943,7 +944,7 @@ public abstract class AuthorityResource uriInfo = new UriInfoWrapper(uriInfo); return updateItemWorkflowWithTransition(null, uriInfo, parentIdentifier, itemIdentifier, transition); } - + public byte[] updateItemWorkflowWithTransition( ServiceContext existingContext, UriInfo uriInfo, @@ -1065,7 +1066,7 @@ public abstract class AuthorityResource } result = (PoxPayloadOut) ctx.getOutput(); - if (result != null) { + if (result != null && !parentcsid.equals(PARENT_WILDCARD)) { String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY); if (inAuthority.equalsIgnoreCase(parentcsid) == false) { throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.", @@ -1544,7 +1545,7 @@ public abstract class AuthorityResource String xmlPayload) { return updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, xmlPayload); } - + public byte[] updateAuthorityItem( ServiceContext parentCtx, ResourceMap resourceMap, @@ -1740,4 +1741,20 @@ public abstract class AuthorityResource return csid; } + public static AuthorityResource getResourceForItem(ResourceMap resourceMap, String tenantId, String itemDocType) { + for (String serviceName : resourceMap.keySet()) { + CollectionSpaceResource resource = (CollectionSpaceResource) resourceMap.get(serviceName); + + if (resource instanceof AuthorityResource) { + AuthorityResource authorityResource = (AuthorityResource) resource; + String docType = authorityResource.getItemDocType(tenantId); + + if (docType.equals(itemDocType)) { + return authorityResource; + } + } + } + + return null; + } } diff --git a/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto-unified.xml b/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto-unified.xml index 412d1823e..58494adce 100644 --- a/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto-unified.xml +++ b/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto-unified.xml @@ -375,6 +375,44 @@ + + + default-domain + org.collectionspace.services.export.nuxeo.ExportDocumentModelHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/invocable/Invocable.java b/services/common/src/main/java/org/collectionspace/services/common/invocable/Invocable.java index f0863c139..03dd98c10 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/invocable/Invocable.java +++ b/services/common/src/main/java/org/collectionspace/services/common/invocable/Invocable.java @@ -22,7 +22,6 @@ */ package org.collectionspace.services.common.invocable; -import org.collectionspace.services.common.invocable.InvocationContext; import java.util.List; import org.collectionspace.services.client.PoxPayloadIn; @@ -64,16 +63,16 @@ public interface Invocable { @Override public String toString() { - return (Tools.notBlank(message)) ? message : "No error message provided"; + return (Tools.notBlank(message)) ? message : "No error message provided"; } } - - public String INVOCATION_MODE_SINGLE = "single"; - public String INVOCATION_MODE_LIST = "list"; - public String INVOCATION_MODE_GROUP = "group"; - public String INVOCATION_MODE_NO_CONTEXT = "nocontext"; - //public String INVOCATION_MODE_QUERY = "query"; NYI - + + public final String INVOCATION_MODE_SINGLE = "single"; + public final String INVOCATION_MODE_LIST = "list"; + public final String INVOCATION_MODE_GROUP = "group"; + public final String INVOCATION_MODE_NO_CONTEXT = "nocontext"; + public final String INVOCATION_MODE_QUERY = "query"; + public final int STATUS_ERROR = -1; public final int STATUS_UNSTARTED = 0; public final int STATUS_MIN_PROGRESS = 1; diff --git a/services/export/build.xml b/services/export/build.xml new file mode 100644 index 000000000..1eaaba2ee --- /dev/null +++ b/services/export/build.xml @@ -0,0 +1,108 @@ + + + + export service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/export/client/pom.xml b/services/export/client/pom.xml new file mode 100644 index 000000000..3b257b2ca --- /dev/null +++ b/services/export/client/pom.xml @@ -0,0 +1,83 @@ + + + + org.collectionspace.services + org.collectionspace.services.export + ${revision} + + + 4.0.0 + org.collectionspace.services.export.client + services.export.client + + + + + org.collectionspace.services + org.collectionspace.services.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.common + true + + + org.collectionspace.services + org.collectionspace.services.export.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.person.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.acquisition.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.acquisition.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.organization.client + ${project.version} + + + + org.testng + testng + + + org.jboss.resteasy + resteasy-jaxrs + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + resteasy-multipart-provider + + + commons-httpclient + commons-httpclient + + + + + collectionspace-services-export-client + + diff --git a/services/export/client/src/main/java/org/collectionspace/services/client/ExportClient.java b/services/export/client/src/main/java/org/collectionspace/services/client/ExportClient.java new file mode 100644 index 000000000..e4bc824b8 --- /dev/null +++ b/services/export/client/src/main/java/org/collectionspace/services/client/ExportClient.java @@ -0,0 +1,67 @@ +/** + * ExportClient.java + * + * {Purpose of This Class} + * + * {Other Notes Relating to This Class (Optional)} + * + * $LastChangedBy: $ + * $LastChangedRevision: $ + * $LastChangedDate: $ + * + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright (c) 2009 {Contributing Institution} + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.client; + +import javax.ws.rs.core.Response; + +import org.collectionspace.services.common.invocable.InvocationContext; +import org.collectionspace.services.export.ExportsCommon; + +/** + * An Export client. + + * @version $Revision:$ + */ +public class ExportClient extends AbstractCommonListPoxServiceClientImpl { + public static final String SERVICE_NAME = "exports"; + public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME; + public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT; + public static final String SERVICE_COMMON_PART_NAME = SERVICE_NAME + PART_LABEL_SEPARATOR + PART_COMMON_LABEL; + + public ExportClient() throws Exception { + super(); + } + + public ExportClient(String clientPropertiesFilename) throws Exception { + super(clientPropertiesFilename); + } + + @Override + public String getServiceName() { + return SERVICE_NAME; + } + + @Override + public String getServicePathComponent() { + return SERVICE_PATH_COMPONENT; + } + + @Override + public Class getProxyClass() { + return ExportProxy.class; + } +} diff --git a/services/export/client/src/main/java/org/collectionspace/services/client/ExportProxy.java b/services/export/client/src/main/java/org/collectionspace/services/client/ExportProxy.java new file mode 100644 index 000000000..705f3c81e --- /dev/null +++ b/services/export/client/src/main/java/org/collectionspace/services/client/ExportProxy.java @@ -0,0 +1,48 @@ +/** + * ExportProxy.java + * + * {Purpose of This Class} + * + * {Other Notes Relating to This Class (Optional)} + * + * $LastChangedBy: $ + * $LastChangedRevision: $ + * $LastChangedDate: $ + * + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright © 2009 {Contributing Institution} + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.client; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; + +import org.collectionspace.services.common.invocable.InvocationContext; + +/** + * @version $Revision:$ + * FIXME: http://issues.collectionspace.org/browse/CSPACE-1684 + */ +@Path("/exports/") +@Produces({"application/xml;charset=UTF-8"}) +@Consumes({"application/xml"}) +public interface ExportProxy extends CollectionSpaceCommonListPoxProxy { +} diff --git a/services/export/jaxb/.gitignore b/services/export/jaxb/.gitignore new file mode 100644 index 000000000..e91d5c41b --- /dev/null +++ b/services/export/jaxb/.gitignore @@ -0,0 +1,3 @@ +/target/ +/target/ +/target/ diff --git a/services/export/jaxb/pom.xml b/services/export/jaxb/pom.xml new file mode 100644 index 000000000..b5cea75cc --- /dev/null +++ b/services/export/jaxb/pom.xml @@ -0,0 +1,33 @@ + + + + org.collectionspace.services.export + org.collectionspace.services + ${revision} + + + 4.0.0 + org.collectionspace.services.export.jaxb + services.export.jaxb + + + + org.collectionspace.services + org.collectionspace.services.jaxb + ${project.version} + + + + + collectionspace-services-export-jaxb + install + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + + + + diff --git a/services/export/jaxb/src/main/java/org/collectionspace/services/ExportJAXBSchema.java b/services/export/jaxb/src/main/java/org/collectionspace/services/ExportJAXBSchema.java new file mode 100644 index 000000000..c30f5381d --- /dev/null +++ b/services/export/jaxb/src/main/java/org/collectionspace/services/ExportJAXBSchema.java @@ -0,0 +1,9 @@ +/** + * + */ +package org.collectionspace.services; + +import org.collectionspace.services.jaxb.InvocableJAXBSchema; + +public interface ExportJAXBSchema extends InvocableJAXBSchema { +} diff --git a/services/export/jaxb/src/main/resources/exports-common.xsd b/services/export/jaxb/src/main/resources/exports-common.xsd new file mode 100644 index 000000000..95e981c61 --- /dev/null +++ b/services/export/jaxb/src/main/resources/exports-common.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + diff --git a/services/export/pom.xml b/services/export/pom.xml new file mode 100644 index 000000000..72b75d3bf --- /dev/null +++ b/services/export/pom.xml @@ -0,0 +1,25 @@ + + + + + org.collectionspace.services + org.collectionspace.services.main + ${revision} + + + 4.0.0 + org.collectionspace.services + org.collectionspace.services.export + services.export + pom + + + + + + jaxb + service + client + + diff --git a/services/export/service/pom.xml b/services/export/service/pom.xml new file mode 100644 index 000000000..2cd3e7114 --- /dev/null +++ b/services/export/service/pom.xml @@ -0,0 +1,122 @@ + + + + + org.collectionspace.services + org.collectionspace.services.export + ${revision} + + + 4.0.0 + org.collectionspace.services.export.service + services.export.service + jar + + + + org.collectionspace.services + org.collectionspace.services.authentication.service + ${project.version} + provided + + + org.collectionspace.services + org.collectionspace.services.account.service + ${project.version} + provided + + + org.collectionspace.services + org.collectionspace.services.authority.service + ${project.version} + provided + + + org.collectionspace.services + org.collectionspace.services.config + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.authority.jaxb + true + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.common + + + org.collectionspace.services + org.collectionspace.services.export.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.export.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.collectionobject.jaxb + ${project.version} + + + + junit + junit + test + + + org.testng + testng + + + org.apache.commons + commons-csv + 1.8 + + + + + + javax.security + jaas + 1.0.01 + provided + + + + + + org.jboss.resteasy + resteasy-jaxrs + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + resteasy-multipart-provider + + + + + + org.nuxeo.ecm.core + nuxeo-core-api + + + jboss-remoting + jboss + + + + + + + + collectionspace-services-export + + diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/AbstractDocumentsByQueryIterator.java b/services/export/service/src/main/java/org/collectionspace/services/export/AbstractDocumentsByQueryIterator.java new file mode 100644 index 000000000..9a6ad7027 --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/AbstractDocumentsByQueryIterator.java @@ -0,0 +1,244 @@ +package org.collectionspace.services.export; + +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.utils.URIBuilder; +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.NuxeoBasedResource; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceBindingUtils; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.invocable.InvocationContext; +import org.collectionspace.services.common.query.UriInfoImpl; +import org.collectionspace.services.common.vocabulary.AuthorityResource; +import org.collectionspace.services.config.service.ServiceBindingType; +import org.collectionspace.services.jaxb.AbstractCommonList; +import org.jboss.resteasy.specimpl.PathSegmentImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractDocumentsByQueryIterator implements Iterator { + private final Logger logger = LoggerFactory.getLogger(AbstractDocumentsByQueryIterator.class); + + private NuxeoBasedResource resource; + private String vocabulary; + private boolean isAuthorityItem = false; + private AbstractCommonList resultList; + private Iterator resultItemIterator; + private InvocationContext.Query query; + + protected ServiceContext serviceContext; + + AbstractDocumentsByQueryIterator( + ServiceContext serviceContext, + String docType, + String vocabulary, + InvocationContext.Query query) throws Exception { + + TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader(); + ServiceBindingType serviceBinding = tenantBindingConfigReader.getServiceBindingForDocType(serviceContext.getTenantId(), docType); + String serviceType = serviceBinding.getType(); + String serviceName = serviceBinding.getName(); + + this.serviceContext = serviceContext; + this.isAuthorityItem = ServiceBindingUtils.SERVICE_TYPE_AUTHORITY.equals(serviceType); + this.vocabulary = vocabulary; + + this.resource = isAuthorityItem + ? AuthorityResource.getResourceForItem(serviceContext.getResourceMap(), serviceContext.getTenantId(), docType) + : (NuxeoBasedResource) serviceContext.getResource(serviceName.toLowerCase()); + + this.query = query; + + getResults(query); + } + + private void getResults(InvocationContext.Query query) throws Exception { + UriInfo uriInfo = createUriInfo(query); + + resultList = isAuthorityItem + ? ((AuthorityResource) resource).getAuthorityItemList(serviceContext, vocabulary == null ? AuthorityResource.PARENT_WILDCARD : vocabulary, uriInfo) + : resource.getList(serviceContext, uriInfo); + + resultItemIterator = (resultList == null) ? null : getListItems(resultList).iterator(); + } + + protected abstract List getListItems(AbstractCommonList list); + + private boolean hasMoreResultPages() { + if (resultList == null || query.getPgNum() != null) { + return false; + } + + long pageSize = resultList.getPageSize(); + long pageNum = resultList.getPageNum(); + long totalItems = resultList.getTotalItems(); + + return (totalItems > (pageSize * (pageNum + 1))); + } + + private void getNextResultPage() throws Exception { + if (hasMoreResultPages()) { + long pageSize = resultList.getPageSize(); + long pageNum = resultList.getPageNum(); + + InvocationContext.Query nextPageQuery = new InvocationContext.Query(); + + nextPageQuery.setAs(query.getAs()); + nextPageQuery.setKw(query.getKw()); + nextPageQuery.setPgNum(BigInteger.valueOf(pageNum + 1)); + nextPageQuery.setPgSz(BigInteger.valueOf(pageSize)); + nextPageQuery.setWfDeleted(query.isWfDeleted()); + + getResults(nextPageQuery); + } + } + + @Override + public boolean hasNext() { + return ( + resultList != null + && resultItemIterator != null + && (resultItemIterator.hasNext() || hasMoreResultPages()) + ); + } + + @Override + public PoxPayloadOut next() { + if (resultList == null || resultItemIterator == null) { + throw new NoSuchElementException(); + } + + if (!resultItemIterator.hasNext()) { + if (!hasMoreResultPages()) { + throw new NoSuchElementException(); + } + + try { + getNextResultPage(); + } + catch (Exception e) { + logger.warn("Could not get result page", e); + + return null; + } + } + + return getDocument(resultItemIterator.next()); + } + + protected PoxPayloadOut getDocument(ListItemType item) { + String csid = getListItemCsid(item); + + try { + return (isAuthorityItem + ? ((AuthorityResource) resource).getAuthorityItemWithExistingContext(serviceContext, AuthorityResource.PARENT_WILDCARD, csid) + : resource.getWithParentCtx(serviceContext, csid)); + } + catch (Exception e) { + logger.warn("Could not get document with csid " + csid, e); + + return null; + } + } + + protected abstract String getListItemCsid(ListItemType listItem); + + protected UriInfo createUriInfo(InvocationContext.Query query) throws URISyntaxException { + URI absolutePath = new URI(""); + URI baseUri = new URI(""); + String encodedPath = ""; + + // Some code in services assumes pathSegments will have at least one element, so add an + // empty one. + List pathSegments = Arrays.asList((PathSegment) new PathSegmentImpl("", false)); + + URIBuilder uriBuilder = new URIBuilder(); + + String as = query.getAs(); + + if (StringUtils.isNotEmpty(as)) { + uriBuilder.addParameter("as", as); + } + + String kw = query.getKw(); + + if (StringUtils.isNotEmpty(kw)) { + uriBuilder.addParameter("kw", kw); + } + + BigInteger pgNum = query.getPgNum(); + + if (pgNum != null) { + uriBuilder.addParameter("pgNum", pgNum.toString()); + } + + BigInteger pgSz = query.getPgSz(); + + if (pgSz != null) { + uriBuilder.addParameter("pgSz", pgSz.toString()); + } + + Boolean wfDeleted = query.isWfDeleted(); + + if (wfDeleted != null) { + uriBuilder.addParameter("wf_deleted", Boolean.toString(wfDeleted)); + } + + String sbj = query.getSbj(); + + if (StringUtils.isNotEmpty(sbj)) { + uriBuilder.addParameter("sbj", sbj); + } + + String sbjType = query.getSbjType(); + + if (StringUtils.isNotEmpty(sbjType)) { + uriBuilder.addParameter("sbjType", sbjType); + } + + String prd = query.getPrd(); + + if (StringUtils.isNotEmpty(prd)) { + uriBuilder.addParameter("prd", prd); + } + + String obj = query.getObj(); + + if (StringUtils.isNotEmpty(obj)) { + uriBuilder.addParameter("obj", obj); + } + + String objType = query.getObjType(); + + if (StringUtils.isNotEmpty(objType)) { + uriBuilder.addParameter("objType", objType); + } + + Boolean andReciprocal = query.isAndReciprocal(); + + if (andReciprocal != null) { + uriBuilder.addParameter("andReciprocal", Boolean.toString(andReciprocal)); + } + + String queryString = uriBuilder.toString(); + + if (StringUtils.isNotEmpty(queryString)) { + queryString = queryString.substring(1); // Remove ? from beginning + } + + return new UriInfoImpl(absolutePath, baseUri, encodedPath, queryString, pathSegments); + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/AbstractExportWriter.java b/services/export/service/src/main/java/org/collectionspace/services/export/AbstractExportWriter.java new file mode 100644 index 000000000..80d1fd02a --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/AbstractExportWriter.java @@ -0,0 +1,57 @@ +package org.collectionspace.services.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.HashSet; +import java.util.Set; + +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.invocable.InvocationContext; + +public abstract class AbstractExportWriter implements ExportWriter { + protected InvocationContext invocationContext; + protected ServiceContext serviceContext; + protected TenantBindingConfigReaderImpl tenantBindingConfigReader; + protected Writer writer; + + @Override + public void setInvocationContext(InvocationContext invocationContext) { + this.invocationContext = invocationContext; + } + + @Override + public void setOutputStream(OutputStream outputStream) { + this.writer = new OutputStreamWriter(outputStream); + } + + @Override + public void setServiceContext(ServiceContext serviceContext) { + this.serviceContext = serviceContext; + } + + @Override + public void setTenantBindingConfigReader(TenantBindingConfigReaderImpl tenantBindingConfigReader) { + this.tenantBindingConfigReader = tenantBindingConfigReader; + } + + @Override + public void start() throws Exception { + }; + + @Override + public abstract void writeDocument(PoxPayloadOut document) throws Exception; + + @Override + public void finish() throws Exception { + } + + @Override + public void close() throws Exception { + writer.close(); + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/CsvExportWriter.java b/services/export/service/src/main/java/org/collectionspace/services/export/CsvExportWriter.java new file mode 100644 index 000000000..fb404d543 --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/CsvExportWriter.java @@ -0,0 +1,209 @@ +package org.collectionspace.services.export; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.lang.StringUtils; +import org.collectionspace.services.client.PayloadOutputPart; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.api.RefNameUtils; +import org.collectionspace.services.common.context.ServiceBindingUtils; +import org.collectionspace.services.common.invocable.InvocationContext; +import org.collectionspace.services.config.service.ServiceBindingType; +import org.collectionspace.services.config.service.ServiceObjectType; +import org.dom4j.Element; +import org.dom4j.Namespace; +import org.dom4j.Node; +import org.dom4j.VisitorSupport; + +public class CsvExportWriter extends AbstractExportWriter { + private static final Pattern VALID_FIELD_XPATH_PATTERN = Pattern.compile("^\\w+:(\\w+\\/)*(\\w+)$"); + private static final String AUTH_ITEM_TERM_GROUP_SUFFIX = "TermGroup"; + + private CSVPrinter csvPrinter; + private Map>> refFieldsByDocType = new HashMap<>(); + + @Override + public void start() throws Exception { + // For CSV output, the invocation context must specify the exact fields to be included + // (no wildcard xpaths), so that the columns can be known in advance. Otherwise the entire + // result set would need to be scanned first, in order to determine the fields that are + // present. + + InvocationContext.IncludeFields includeFields = invocationContext.getIncludeFields(); + List fields = (includeFields != null ? includeFields.getField() : new ArrayList()); + + if (fields.size() == 0) { + throw new Exception("For CSV output, the fields to export must be specified using includeFields."); + } + + List headers = new ArrayList<>(); + + for (String field : fields) { + Matcher matcher = VALID_FIELD_XPATH_PATTERN.matcher(field); + + if (!matcher.matches()) { + throw new Exception("The includeField XPath expression \"" + field + "\" is not valid for CSV output. For CSV output, all included fields must be individually specified without using wildcards."); + } + + String fieldName = matcher.group(2); + + headers.add(fieldName); + + if (isFieldWithinAuthItemTermGroup(field)) { + headers.add(fieldName + "NonPreferred"); + } + } + + String[] headersArray = new String[headers.size()]; + + this.csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.withHeader(headers.toArray(headersArray))); + } + + @Override + public void writeDocument(PoxPayloadOut document) throws Exception { + InvocationContext.IncludeFields includeFields = invocationContext.getIncludeFields(); + + if (includeFields == null) { + return; + } + + List fields = includeFields.getField(); + List csvRecord = new ArrayList<>(); + + for (String field : fields) { + if (isFieldWithinAuthItemTermGroup(field)) { + // Write a column for values within the preferred (primary) term group. + csvRecord.add(collectValues(document, field.replace(AUTH_ITEM_TERM_GROUP_SUFFIX + "/", AUTH_ITEM_TERM_GROUP_SUFFIX + "[position()=1]/"))); + + // Write a column for values within non-preferred term groups. + csvRecord.add(collectValues(document, field.replace(AUTH_ITEM_TERM_GROUP_SUFFIX + "/", AUTH_ITEM_TERM_GROUP_SUFFIX + "[position()>1]/"))); + } + else { + csvRecord.add(collectValues(document, field)); + } + } + + if (csvRecord.size() > 0) { + csvPrinter.printRecord(csvRecord); + } + } + + @Override + public void close() throws Exception { + csvPrinter.close(); + } + + private boolean isFieldWithinAuthItemTermGroup(String field) { + // FIXME: How to know a NonPreferred column is needed without hardcoding "TermGroup"? + + return field.contains(AUTH_ITEM_TERM_GROUP_SUFFIX + "/"); + } + + private String collectValues(PoxPayloadOut document, String field) { + String delimitedValues = ""; + String[] segments = field.split(":", 2); + String partName = segments[0]; + String xpath = segments[1]; + + PayloadOutputPart part = document.getPart(partName); + + if (part != null) { + delimitedValues = collectValues(document.getName(), partName, part.getElementBody(), Arrays.asList(xpath.split("/")), 0); + } + + return delimitedValues; + } + + private String collectValues(String docType, String partName, Element element, List path, int depth) { + String delimitedValues = ""; + String fieldName = path.get(depth); + String delimiter = (depth / 2 > 0) ? "^^" : ";"; + List matches = element.createXPath(fieldName).selectNodes(element); + + if (matches.size() > 0) { + List values = new ArrayList<>(); + boolean hasValue = false; + + for (Node node : matches) { + String textValue = ""; + + if (depth < path.size() - 1) { + textValue = collectValues(docType, partName, (Element) node, path, depth + 1); + } + else { + textValue = node.getText(); + + boolean isRefName = isRefField(docType, partName, fieldName); + + if (isRefName && StringUtils.isNotEmpty(textValue)) { + textValue = RefNameUtils.getDisplayName(textValue); + } + } + + if (StringUtils.isNotEmpty(textValue)) { + hasValue = true; + } + + values.add(textValue); + } + + if (hasValue) { + delimitedValues = String.join(delimiter, values); + } + } + + return delimitedValues; + } + + private boolean isRefField(String docType, String partName, String fieldName) { + return getRefFields(docType, partName).contains(fieldName); + } + + private Set getRefFields(String docType, String partName) { + Set refFields = refFieldsByDocType.containsKey(docType) + ? refFieldsByDocType.get(docType).get(partName) + : null; + + if (refFields != null) { + return refFields; + } + + refFields = new HashSet<>(); + + ServiceBindingType serviceBinding = tenantBindingConfigReader.getServiceBinding(serviceContext.getTenantId(), docType); + + for (String termRefField : ServiceBindingUtils.getPropertyValuesForPart(serviceBinding, partName, ServiceBindingUtils.TERM_REF_PROP, false)) { + String[] segments = termRefField.split("[\\/\\|]"); + String fieldName = segments[segments.length - 1]; + + refFields.add(fieldName); + } + + for (String authRefField : ServiceBindingUtils.getPropertyValuesForPart(serviceBinding, partName, ServiceBindingUtils.AUTH_REF_PROP, false)) { + String[] segments = authRefField.split("[\\/\\|]"); + String fieldName = segments[segments.length - 1]; + + refFields.add(fieldName); + } + + if (!refFieldsByDocType.containsKey(docType)) { + refFieldsByDocType.put(docType, new HashMap>()); + } + + refFieldsByDocType.get(docType).put(partName, refFields); + + return refFields; + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByCsidIterator.java b/services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByCsidIterator.java new file mode 100644 index 000000000..787065b75 --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByCsidIterator.java @@ -0,0 +1,68 @@ +package org.collectionspace.services.export; + +import java.util.Iterator; +import java.util.List; + +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.NuxeoBasedResource; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceBindingUtils; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.vocabulary.AuthorityResource; +import org.collectionspace.services.config.service.ServiceBindingType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DocumentsByCsidIterator implements Iterator { + private final Logger logger = LoggerFactory.getLogger(DocumentsByCsidIterator.class); + + private NuxeoBasedResource resource; + private String vocabulary; + private ServiceContext serviceContext; + private Iterator csidIterator; + private boolean isAuthorityItem = false; + + DocumentsByCsidIterator( + ServiceContext serviceContext, + String docType, + String vocabulary, + List csids) throws Exception { + + TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader(); + ServiceBindingType serviceBinding = tenantBindingConfigReader.getServiceBindingForDocType(serviceContext.getTenantId(), docType); + String serviceType = serviceBinding.getType(); + String serviceName = serviceBinding.getName(); + + this.serviceContext = serviceContext; + this.csidIterator = csids.iterator(); + this.isAuthorityItem = ServiceBindingUtils.SERVICE_TYPE_AUTHORITY.equals(serviceType); + this.vocabulary = vocabulary; + + this.resource = isAuthorityItem + ? AuthorityResource.getResourceForItem(serviceContext.getResourceMap(), serviceContext.getTenantId(), docType) + : (NuxeoBasedResource) serviceContext.getResource(serviceName.toLowerCase()); + } + + @Override + public boolean hasNext() { + return csidIterator.hasNext(); + } + + @Override + public PoxPayloadOut next() { + String csid = csidIterator.next(); + + try { + return (isAuthorityItem + ? ((AuthorityResource) resource).getAuthorityItemWithExistingContext(serviceContext, vocabulary == null ? AuthorityResource.PARENT_WILDCARD : vocabulary, csid) + : resource.getWithParentCtx(serviceContext, csid)); + } + catch (Exception e) { + logger.warn("Could not get document with csid " + csid, e); + + return null; + } + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByGroupIterator.java b/services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByGroupIterator.java new file mode 100644 index 000000000..20fd25c5d --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/DocumentsByGroupIterator.java @@ -0,0 +1,40 @@ +package org.collectionspace.services.export; + +import java.util.Iterator; + +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.client.RelationClient; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.invocable.InvocationContext; + +public class DocumentsByGroupIterator implements Iterator { + private RelationObjectsByQueryIterator relationsIterator; + + DocumentsByGroupIterator( + ServiceContext serviceContext, + String csid) throws Exception { + + InvocationContext.Query query = new InvocationContext.Query(); + + query.setSbjType("Group"); + query.setSbj(csid); + query.setPrd("affects"); + query.setWfDeleted(false); + + relationsIterator = new RelationObjectsByQueryIterator(serviceContext, RelationClient.SERVICE_DOC_TYPE, null, query); + } + + @Override + public boolean hasNext() { + return ( + relationsIterator != null + && relationsIterator.hasNext() + ); + } + + @Override + public PoxPayloadOut next() { + return relationsIterator.next(); + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/ExportResource.java b/services/export/service/src/main/java/org/collectionspace/services/export/ExportResource.java new file mode 100644 index 000000000..b1e76cb6d --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/ExportResource.java @@ -0,0 +1,371 @@ +/** + * 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.export; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.collectionspace.services.client.ExportClient; +import org.collectionspace.services.client.PayloadOutputPart; +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.client.RelationClient; +import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl; +import org.collectionspace.services.common.ServiceMessages; +import org.collectionspace.services.common.context.MultipartServiceContextFactory; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.context.ServiceContextFactory; +import org.collectionspace.services.common.invocable.Invocable; +import org.collectionspace.services.common.invocable.InvocationContext; +import org.dom4j.Node; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +@Path(ExportClient.SERVICE_PATH) +@Consumes("application/xml") +@Produces("application/xml") +public class ExportResource extends AbstractCollectionSpaceResourceImpl { + private final Logger logger = LoggerFactory.getLogger(ExportResource.class); + + // There is no way to tell from config that collectionspace_core should not be exported, so it + // has to be hardcoded here. At that point we might as well also hardcode account_permission, + // so we don't need to look at config at all. + + private static final List EXCLUDE_PARTS = Arrays.asList("collectionspace_core", "account_permission"); + + private static final String MIME_TYPE_CSV = "text/csv"; + private static final String MIME_TYPE_XML = "application/xml"; + private static final String INCLUDE_ATTRIBUTE_NAME = "cspace-export-include"; + + @Override + protected String getVersionString() { + final String lastChangeRevision = "$LastChangedRevision: 1982 $"; + return lastChangeRevision; + } + + @Override + public String getServiceName() { + return ExportClient.SERVICE_NAME; + } + + @Override + public Class getCommonPartClass() { + return ExportsCommon.class; + } + + @Override + public ServiceContextFactory getServiceContextFactory() { + return MultipartServiceContextFactory.get(); + } + + @GET + @Produces("text/html") + public String getInputForm() { + return "Export"; + } + + @POST + public Response invokeExport(@Context UriInfo uriInfo, InvocationContext invocationContext) throws Exception { + String outputMimeType = getOutputMimeType(invocationContext); + + if (!(outputMimeType.equals(MIME_TYPE_XML) || outputMimeType.equals(MIME_TYPE_CSV))) { + throw new Exception("Unsupported output MIME type " + outputMimeType); + } + + String outputFileName = "export." + (outputMimeType.equals(MIME_TYPE_XML) ? "xml" : "csv"); + + try { + ServiceContext serviceContext = createServiceContext(); + InputStream exportStream = invokeExport(serviceContext, invocationContext); + + return Response.ok(exportStream, outputMimeType) + .header("Content-Disposition", "inline;filename=\"" + outputFileName + "\"").build(); + } catch (Exception e) { + String message = e.getMessage(); + + throw bigReThrow(e, ServiceMessages.POST_FAILED + (message != null ? message : "")); + } + } + + private String getOutputMimeType(InvocationContext invocationContext) { + String outputMimeType = invocationContext.getOutputMIME(); + + if (StringUtils.isEmpty(outputMimeType)) { + outputMimeType = MIME_TYPE_XML; + } + + return outputMimeType; + } + + private InputStream invokeExport(ServiceContext serviceContext, + InvocationContext invocationContext) throws Exception { + + Iterator documents = getDocuments(serviceContext, invocationContext); + + return exportDocuments(serviceContext, invocationContext, documents); + } + + private InputStream exportDocuments(ServiceContext serviceContext, + InvocationContext invocationContext, Iterator documents) throws Exception { + + File exportFile = File.createTempFile("export-", null); + FileOutputStream outputStream = new FileOutputStream(exportFile); + ExportWriter exportWriter = getExportWriter(serviceContext, invocationContext, outputStream); + + exportWriter.start(); + + while (documents.hasNext()) { + PoxPayloadOut document = documents.next(); + + if (document != null) { + filterFields(document, invocationContext); + + exportWriter.writeDocument(document); + } + } + + exportWriter.finish(); + exportWriter.close(); + + return new FileInputStream(exportFile); + } + + private void filterFields(PoxPayloadOut document, InvocationContext invocationContext) { + if (document == null) { + return; + } + + for (String partName : EXCLUDE_PARTS) { + PayloadOutputPart part = document.getPart(partName); + + if (part != null) { + document.removePart(part); + } + } + + InvocationContext.ExcludeFields excludeFields = invocationContext.getExcludeFields(); + + if (excludeFields != null) { + List fields = excludeFields.getField(); + + for (String field : fields) { + String[] segments = field.split(":", 2); + + String partName = segments[0]; + String xpath = segments[1]; + + PayloadOutputPart part = document.getPart(partName); + + if (part != null) { + org.dom4j.Element partElement = part.getElementBody(); + List matches = (List) partElement.createXPath(xpath).selectNodes(partElement); + + for (Node excludeNode : matches) { + if (excludeNode.getNodeType() == Node.ELEMENT_NODE) { + excludeNode.detach(); + } + } + } + } + } + + InvocationContext.IncludeFields includeFields = invocationContext.getIncludeFields(); + + if (includeFields != null) { + List fields = includeFields.getField(); + + for (String field : fields) { + String[] segments = field.split(":", 2); + + String partName = segments[0]; + String xpath = segments[1]; + + PayloadOutputPart part = document.getPart(partName); + + if (part != null) { + org.dom4j.Element partElement = part.getElementBody(); + List matches = (List) partElement.createXPath(xpath).selectNodes(partElement); + + for (Node includeNode : matches) { + if (includeNode.getNodeType() == Node.ELEMENT_NODE) { + markIncluded((org.dom4j.Element) includeNode); + } + } + } + } + + ArrayList includedParts = new ArrayList<>(); + + for (PayloadOutputPart part : document.getParts()) { + org.dom4j.Element partElement = part.getElementBody(); + + if (partElement.attributeValue(INCLUDE_ATTRIBUTE_NAME) != null) { + includedParts.add(part); + removeUnincluded(partElement); + } + } + + document.setParts(includedParts); + } + } + + private void markIncluded(org.dom4j.Element element) { + org.dom4j.Element parentElement = element.getParent(); + + if (parentElement != null) { + markIncluded(parentElement); + } + + element.addAttribute(INCLUDE_ATTRIBUTE_NAME, "1"); + } + + private void removeUnincluded(org.dom4j.Element element) { + if (element.attributeValue(INCLUDE_ATTRIBUTE_NAME) == null) { + element.detach(); + } + else { + element.addAttribute(INCLUDE_ATTRIBUTE_NAME, null); + + Iterator childIterator = element.elementIterator(); + + while (childIterator.hasNext()) { + org.dom4j.Element childElement = (org.dom4j.Element) childIterator.next(); + + removeUnincluded(childElement); + } + } + } + + private ExportWriter getExportWriter( + ServiceContext serviceContext, + InvocationContext invocationContext, + OutputStream outputStream) { + + String outputMimeType = getOutputMimeType(invocationContext); + AbstractExportWriter exportWriter = null; + + if (outputMimeType.equals(MIME_TYPE_XML)) { + exportWriter = new XmlExportWriter(); + } + else if (outputMimeType.equals(MIME_TYPE_CSV)) { + exportWriter = new CsvExportWriter(); + } + + if (exportWriter != null) { + exportWriter.setInvocationContext(invocationContext); + exportWriter.setOutputStream(outputStream); + exportWriter.setServiceContext(serviceContext); + exportWriter.setTenantBindingConfigReader(getTenantBindingsReader()); + } + + return exportWriter; + } + + private Iterator getDocuments( + ServiceContext serviceContext, + InvocationContext invocationContext) throws Exception { + + String targetDocType = invocationContext.getDocType(); + String targetVocabulary = invocationContext.getVocabulary(); + + switch (invocationContext.getMode().toLowerCase()) { + case Invocable.INVOCATION_MODE_QUERY: + return getDocumentsByQuery(serviceContext, targetDocType, targetVocabulary, invocationContext.getQuery()); + case Invocable.INVOCATION_MODE_SINGLE: + return getDocumentByCsid(serviceContext, targetDocType, targetVocabulary, invocationContext.getSingleCSID()); + case Invocable.INVOCATION_MODE_LIST: + return getDocumentsByCsid(serviceContext, targetDocType, targetVocabulary, invocationContext.getListCSIDs().getCsid()); + case Invocable.INVOCATION_MODE_GROUP: + return getDocumentsByGroup(serviceContext, invocationContext.getGroupCSID()); + case Invocable.INVOCATION_MODE_NO_CONTEXT: + return getDocumentsByType(serviceContext, targetDocType, targetVocabulary); + default: + throw new UnsupportedOperationException("Unsupported invocation mode: " + invocationContext.getMode()); + } + } + + private Iterator getDocumentsByType( + ServiceContext serviceContext, + String docType, + String vocabulary) throws Exception { + + return getDocumentsByQuery(serviceContext, docType, vocabulary, new InvocationContext.Query()); + } + + private Iterator getDocumentsByQuery( + ServiceContext serviceContext, + String docType, + String vocabulary, + InvocationContext.Query query) throws Exception { + + if (RelationClient.SERVICE_DOC_TYPE.equals(docType)) { + return new RelationsByQueryIterator(serviceContext, docType, vocabulary, query); + } + + return new StandardDocumentsByQueryIterator(serviceContext, docType, vocabulary, query); + } + + private Iterator getDocumentByCsid( + ServiceContext serviceContext, + String docType, + String vocabulary, + String csid) throws Exception { + + return getDocumentsByCsid(serviceContext, docType, vocabulary, Arrays.asList(csid)); + } + + private Iterator getDocumentsByCsid( + ServiceContext serviceContext, + String docType, + String vocabulary, + List csids) throws Exception { + + return new DocumentsByCsidIterator(serviceContext, docType, vocabulary, csids); + } + + private Iterator getDocumentsByGroup( + ServiceContext serviceContext, + String csid) throws Exception { + + return new DocumentsByGroupIterator(serviceContext, csid); + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/ExportWriter.java b/services/export/service/src/main/java/org/collectionspace/services/export/ExportWriter.java new file mode 100644 index 000000000..fc8f71963 --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/ExportWriter.java @@ -0,0 +1,23 @@ +package org.collectionspace.services.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; + +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.invocable.InvocationContext; + +public interface ExportWriter { + public void setInvocationContext(InvocationContext invocationContext); + public void setOutputStream(OutputStream outputStream); + public void setServiceContext(ServiceContext serviceContext); + public void setTenantBindingConfigReader(TenantBindingConfigReaderImpl tenantBindingConfigReader); + + public void start() throws Exception; + public void writeDocument(PoxPayloadOut document) throws Exception; + public void finish() throws Exception; + public void close() throws Exception; +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/RelationObjectsByQueryIterator.java b/services/export/service/src/main/java/org/collectionspace/services/export/RelationObjectsByQueryIterator.java new file mode 100644 index 000000000..857bb2426 --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/RelationObjectsByQueryIterator.java @@ -0,0 +1,61 @@ +package org.collectionspace.services.export; + +import java.util.Iterator; + +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.NuxeoBasedResource; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceBindingUtils; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.invocable.InvocationContext; +import org.collectionspace.services.common.vocabulary.AuthorityResource; +import org.collectionspace.services.config.service.ServiceBindingType; +import org.collectionspace.services.relation.RelationsCommonList.RelationListItem; +import org.collectionspace.services.relation.RelationsDocListItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RelationObjectsByQueryIterator extends RelationsByQueryIterator implements Iterator { + private final Logger logger = LoggerFactory.getLogger(RelationObjectsByQueryIterator.class); + + RelationObjectsByQueryIterator( + ServiceContext serviceContext, + String docType, + String vocabulary, + InvocationContext.Query query) throws Exception { + + super(serviceContext, docType, vocabulary, query); + } + + @Override + protected PoxPayloadOut getDocument(RelationListItem item) { + RelationsDocListItem relationObject = item.getObject(); + + String relationObjectCsid = relationObject.getCsid(); + String relationObjectDocType = relationObject.getDocumentType(); + + TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader(); + ServiceBindingType relationObjectServiceBinding = tenantBindingConfigReader.getServiceBindingForDocType(serviceContext.getTenantId(), relationObjectDocType); + String relationObjectServiceType = relationObjectServiceBinding.getType(); + String relationObjectServiceName = relationObjectServiceBinding.getName(); + + boolean relationObjectIsAuthorityItem = ServiceBindingUtils.SERVICE_TYPE_AUTHORITY.equals(relationObjectServiceType); + + try { + NuxeoBasedResource relationObjectResource = relationObjectIsAuthorityItem + ? AuthorityResource.getResourceForItem(serviceContext.getResourceMap(), serviceContext.getTenantId(), relationObjectDocType) + : (NuxeoBasedResource) serviceContext.getResource(relationObjectServiceName.toLowerCase()); + + return (relationObjectIsAuthorityItem + ? ((AuthorityResource) relationObjectResource).getAuthorityItemWithExistingContext(serviceContext, AuthorityResource.PARENT_WILDCARD, relationObjectCsid) + : relationObjectResource.getWithParentCtx(serviceContext, relationObjectCsid)); + } + catch (Exception e) { + logger.warn("Could not get document with csid " + relationObjectCsid, e); + + return null; + } + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/RelationsByQueryIterator.java b/services/export/service/src/main/java/org/collectionspace/services/export/RelationsByQueryIterator.java new file mode 100644 index 000000000..9e2883f4b --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/RelationsByQueryIterator.java @@ -0,0 +1,34 @@ + +package org.collectionspace.services.export; + +import java.util.Iterator; +import java.util.List; + +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.invocable.InvocationContext; +import org.collectionspace.services.jaxb.AbstractCommonList; +import org.collectionspace.services.relation.RelationsCommonList; +import org.collectionspace.services.relation.RelationsCommonList.RelationListItem; + +public class RelationsByQueryIterator extends AbstractDocumentsByQueryIterator implements Iterator { + RelationsByQueryIterator( + ServiceContext serviceContext, + String docType, + String vocabulary, + InvocationContext.Query query) throws Exception { + + super(serviceContext, docType, vocabulary, query); + } + + @Override + protected List getListItems(AbstractCommonList list) { + return ((RelationsCommonList) list).getRelationListItem(); + } + + @Override + protected String getListItemCsid(RelationListItem listItem) { + return listItem.getCsid(); + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/StandardDocumentsByQueryIterator.java b/services/export/service/src/main/java/org/collectionspace/services/export/StandardDocumentsByQueryIterator.java new file mode 100644 index 000000000..fe85c76df --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/StandardDocumentsByQueryIterator.java @@ -0,0 +1,40 @@ +package org.collectionspace.services.export; + +import java.util.Iterator; +import java.util.List; + +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.invocable.InvocationContext; +import org.collectionspace.services.jaxb.AbstractCommonList; +import org.collectionspace.services.jaxb.AbstractCommonList.ListItem; + +import org.w3c.dom.Element; + +public class StandardDocumentsByQueryIterator extends AbstractDocumentsByQueryIterator implements Iterator { + StandardDocumentsByQueryIterator( + ServiceContext serviceContext, + String docType, + String vocabulary, + InvocationContext.Query query) throws Exception { + + super(serviceContext, docType, vocabulary, query); + } + + @Override + protected List getListItems(AbstractCommonList list) { + return list.getListItem(); + } + + @Override + protected String getListItemCsid(ListItem listItem) { + for (Element element : listItem.getAny()) { + if (element.getTagName().equals("csid")) { + return element.getTextContent(); + } + } + + return null; + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/XmlExportWriter.java b/services/export/service/src/main/java/org/collectionspace/services/export/XmlExportWriter.java new file mode 100644 index 000000000..35ffa549f --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/XmlExportWriter.java @@ -0,0 +1,63 @@ +package org.collectionspace.services.export; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.collectionspace.services.client.PayloadOutputPart; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.config.service.ServiceBindingType; +import org.collectionspace.services.config.service.ServiceObjectType; +import org.dom4j.Element; +import org.dom4j.Namespace; + +public class XmlExportWriter extends AbstractExportWriter { + private int seqNum = 0; + + @Override + public void start() throws Exception { + seqNum = 0; + + writer.write("\n"); + } + + @Override + public void writeDocument(PoxPayloadOut document) throws Exception { + String docType = document.getName(); + ServiceBindingType serviceBinding = tenantBindingConfigReader.getServiceBinding(serviceContext.getTenantId(), docType); + + String serviceName = serviceBinding.getName(); + ServiceObjectType objectConfig = serviceBinding.getObject(); + String objectName = objectConfig.getName(); + + seqNum += 1; + + writer.write(String.format("\n", seqNum, serviceName, objectName)); + + for (PayloadOutputPart part : document.getParts()) { + String partLabel = part.getLabel(); + Element element = part.asElement(); + Namespace partNamespace = element.getNamespaceForPrefix("ns2"); + String partNamespaceUri = partNamespace.getURI(); + + for (Object namespace : element.additionalNamespaces()) { + element.remove((Namespace) namespace); + } + + element.remove(partNamespace); + + element.setName("schema"); + element.addAttribute("name", partLabel); + element.addNamespace(partLabel, partNamespaceUri); + + writer.write(element.asXML()); + } + + writer.write("\n"); + } + + @Override + public void finish() throws Exception { + writer.write(""); + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportConstants.java b/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportConstants.java new file mode 100644 index 000000000..71a6109f0 --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportConstants.java @@ -0,0 +1,31 @@ +/** + * 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.export.nuxeo; + +public class ExportConstants { + public final static String NUXEO_DOCTYPE = "Export"; + public final static String NUXEO_SCHEMA_NAME = "export"; + public final static String DB_COMMON_PART_TABLE_NAME = "exports_common"; + public final static String NUXEO_DC_TITLE = "CollectionSpace-Export"; +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportDocumentModelHandler.java b/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportDocumentModelHandler.java new file mode 100644 index 000000000..a971eb5bb --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportDocumentModelHandler.java @@ -0,0 +1,249 @@ +/** + * 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.export.nuxeo; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MediaType; +import javax.naming.NamingException; +import javax.ws.rs.core.Response; + +import org.apache.commons.lang.StringUtils; +import org.collectionspace.authentication.AuthN; +import org.collectionspace.services.ExportJAXBSchema; +import org.collectionspace.services.account.AccountResource; +import org.collectionspace.services.authorization.AuthZ; +import org.collectionspace.services.authorization.CSpaceResource; +import org.collectionspace.services.authorization.PermissionException; +import org.collectionspace.services.authorization.URIResourceImpl; +import org.collectionspace.services.authorization.perms.ActionType; +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.client.ExportClient; +import org.collectionspace.services.common.CSWebApplicationException; +import org.collectionspace.services.common.NuxeoBasedResource; +import org.collectionspace.services.common.ResourceMap; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.api.JEEServerDeployment; +import org.collectionspace.services.common.api.FileTools; +import org.collectionspace.services.common.api.Tools; +import org.collectionspace.services.common.authorization_mgt.ActionGroup; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceBindingUtils; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.document.BadRequestException; +import org.collectionspace.services.common.document.DocumentException; +import org.collectionspace.services.common.document.DocumentWrapper; +import org.collectionspace.services.common.invocable.Invocable; +import org.collectionspace.services.common.invocable.InvocationContext; +import org.collectionspace.services.common.invocable.InvocationContext.ListCSIDs; +import org.collectionspace.services.common.storage.JDBCTools; +import org.collectionspace.services.config.service.ServiceBindingType; +import org.collectionspace.services.config.types.PropertyItemType; +import org.collectionspace.services.export.ExportsCommon; +import org.collectionspace.services.jaxb.InvocableJAXBSchema; +import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler; +import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface; +import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl; +import org.collectionspace.services.nuxeo.util.NuxeoUtils; + +import org.nuxeo.ecm.core.api.model.PropertyException; +import org.nuxeo.ecm.core.api.DocumentModel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ExportDocumentModelHandler + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class ExportDocumentModelHandler extends NuxeoDocumentModelHandler { + private final Logger logger = LoggerFactory.getLogger(ExportDocumentModelHandler.class); + + public InputStream invokeExport( + TenantBindingConfigReaderImpl tenantBindingReader, + ResourceMap resourceMap, + ServiceContext serviceContext, + InvocationContext invocationContext, + StringBuffer outputMimeType, + StringBuffer outputFileName) throws Exception { + + NuxeoRepositoryClientImpl repoClient = (NuxeoRepositoryClientImpl) this.getRepositoryClient(serviceContext); + boolean releaseRepoSession = false; + CoreSessionInterface repoSession = this.getRepositorySession(); + + if (repoSession == null) { + repoSession = repoClient.getRepositorySession(serviceContext); + releaseRepoSession = true; + } + + try { + Iterator documents = findDocuments(tenantBindingReader, resourceMap, serviceContext, repoSession, invocationContext); + + } + finally { + if (releaseRepoSession && repoSession != null) { + repoClient.releaseRepositorySession(serviceContext, repoSession); + } + } + + return null; + // return buildExportResult(csid, params, exportFileNameProperty, outMimeType.toString(), outExportFileName); + } + + private Iterator findDocuments( + TenantBindingConfigReaderImpl tenantBindingReader, + ResourceMap resourceMap, + ServiceContext serviceContext, + CoreSessionInterface repoSession, + InvocationContext invocationContext) throws Exception { + + String docType = invocationContext.getDocType(); + ServiceBindingType binding = tenantBindingReader.getServiceBindingForDocType(serviceContext.getTenantId(), docType); + String serviceName = binding.getName(); + + switch (invocationContext.getMode().toLowerCase()) { + case Invocable.INVOCATION_MODE_SINGLE: + return findDocumentByCsid(resourceMap, serviceContext, repoSession, serviceName, invocationContext.getSingleCSID()); + case Invocable.INVOCATION_MODE_LIST: + return findDocumentsByCsid(resourceMap, serviceContext, repoSession, serviceName, invocationContext.getListCSIDs().getCsid()); + case Invocable.INVOCATION_MODE_GROUP: + return findDocumentsByGroup(resourceMap, serviceContext, repoSession, invocationContext.getGroupCSID()); + case Invocable.INVOCATION_MODE_NO_CONTEXT: + return findDocumentsByType(resourceMap, serviceContext, repoSession, invocationContext.getDocType()); + default: + return null; + } + } + + private Iterator findDocumentByCsid( + ResourceMap resourceMap, + ServiceContext serviceContext, + CoreSessionInterface repoSession, + String serviceName, + String csid) throws Exception { + + return findDocumentsByCsid(resourceMap, serviceContext, repoSession, serviceName, Arrays.asList(csid)); + } + + private Iterator findDocumentsByCsid( + ResourceMap resourceMap, + ServiceContext serviceContext, + CoreSessionInterface repoSession, + String serviceName, + List csids) throws Exception { + + return new DocumentsByCsidIterator(resourceMap, serviceContext, repoSession, serviceName, csids); + } + + private Iterator findDocumentsByType( + ResourceMap resourceMap, + ServiceContext serviceContext, + CoreSessionInterface repoSession, + String docType) { + + return null; + } + + private Iterator findDocumentsByGroup( + ResourceMap resourceMap, + ServiceContext serviceContext, + CoreSessionInterface repoSession, + String docType) { + + return null; + } + + // private InputStream buildExportResult(String exportCSID, + // HashMap params, + // String exportFileName, + // String outputMimeType, + // StringBuffer outExportFileName) throws Exception { + // Connection conn = null; + // InputStream result = null; + + // return result; + // } + + private class DocumentsByCsidIterator implements Iterator { + private NuxeoBasedResource resource; + private ServiceContext serviceContext; + private CoreSessionInterface repoSession; + private Iterator csidIterator; + + DocumentsByCsidIterator( + ResourceMap resourceMap, + ServiceContext serviceContext, + CoreSessionInterface repoSession, + String serviceName, + List csids) throws Exception { + + NuxeoBasedResource resource = (NuxeoBasedResource) resourceMap.get(serviceName.toLowerCase()); + + if (resource == null) { + throw new Exception("Resource not found for service name " + serviceName); + } + + this.resource = resource; + this.serviceContext = serviceContext; + this.repoSession = repoSession; + this.csidIterator = csids.iterator(); + } + + @Override + public boolean hasNext() { + return csidIterator.hasNext(); + } + + @Override + public DocumentModel next() { + String csid = csidIterator.next(); + + try { + // PoxPayloadOut payload = resource.getWithParentCtx(serviceContext, csid); + return null; + } + catch (Exception e) { + logger.warn("Could not get document with csid " + csid, e); + + return null; + } + } + } +} diff --git a/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportValidatorHandler.java b/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportValidatorHandler.java new file mode 100644 index 000000000..e184902ae --- /dev/null +++ b/services/export/service/src/main/java/org/collectionspace/services/export/nuxeo/ExportValidatorHandler.java @@ -0,0 +1,18 @@ +package org.collectionspace.services.export.nuxeo; + +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.document.InvalidDocumentException; +import org.collectionspace.services.common.document.ValidatorHandler; +import org.collectionspace.services.common.document.DocumentHandler.Action; + +public class ExportValidatorHandler implements ValidatorHandler { + + @Override + public void validate(Action action, ServiceContext ctx) + throws InvalidDocumentException { + // TODO Auto-generated method stub + System.out.println("ExportValidatorHandler executed."); + + } + +} diff --git a/services/jaxb/src/main/resources/invocationContext.xsd b/services/jaxb/src/main/resources/invocationContext.xsd index 2da78da2e..5c970359d 100644 --- a/services/jaxb/src/main/resources/invocationContext.xsd +++ b/services/jaxb/src/main/resources/invocationContext.xsd @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/pom.xml b/services/pom.xml index 5352562df..51a78354f 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -77,6 +77,7 @@ pottag batch imports + export location place work -- 2.47.3