From 9383f4d9fdb455065a324e799c18950d4e6f509e Mon Sep 17 00:00:00 2001 From: Patrick Schmitz Date: Tue, 10 Nov 2009 20:25:58 +0000 Subject: [PATCH] CSPACE-481, CSPACE-590 Added basic support to filter objects in a get, with a default filtering for pagination. Only implemented for Vocabulary at this point. Used this to intelligently filter the vocabularyItems associated to a given vocabulary, and to support finding a vocabulary by name. --- .../context/AbstractServiceContext.java | 15 +++ .../common/context/ServiceContext.java | 16 ++- .../repository/AbstractDocumentHandler.java | 17 +++ .../common/repository/DocumentFilter.java | 107 +++++++++++++++ .../common/repository/DocumentHandler.java | 13 ++ .../common/repository/RepositoryClient.java | 12 +- .../client/java/RepositoryJavaClient.java | 68 +++++++++- .../resources/OSGI-INF/layouts-contrib.xml | 32 ++++- .../resources/schemas/vocabularies_common.xsd | 1 + .../schemas/vocabularyitems_common.xsd | 5 +- .../client/importer/VocabularyBaseImport.java | 127 ++++++++++-------- .../client/test/VocabularyServiceTest.java | 65 ++++++++- .../src/main/resources/vocabulary_common.xsd | 1 + .../main/resources/vocabularyitem_common.xsd | 1 + .../vocabulary/VocabularyResource.java | 73 ++++++++-- .../VocabularyItemDocumentModelHandler.java | 8 +- 16 files changed, 469 insertions(+), 92 deletions(-) create mode 100644 services/common/src/main/java/org/collectionspace/services/common/repository/DocumentFilter.java diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java index aeea00ff3..83696c710 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java @@ -50,6 +50,8 @@ public abstract class AbstractServiceContext private ServiceBindingType serviceBinding; private TenantBindingType tenantBinding; + private String overrideDocumentType = null; + public AbstractServiceContext(String serviceName) { TenantBindingConfigReader tReader = ServiceMain.getInstance().getTenantBindingConfigReader(); @@ -150,6 +152,19 @@ public abstract class AbstractServiceContext @Override public String getServiceName() { return serviceBinding.getName(); + } + + @Override + public String getDocumentType() { + // If they have not overridden the setting, use the type of the service + // object. + return(overrideDocumentType!=null)?overrideDocumentType: + serviceBinding.getObject().get(0).getName(); + } + + @Override + public void setDocumentType(String docType) { + overrideDocumentType = docType; } @Override diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java index c24c261e6..25147efdf 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java @@ -37,7 +37,7 @@ import org.collectionspace.services.common.service.ServiceBindingType; public interface ServiceContext { /** - * The charactor used to separtate the words in a part label + * The character used to separate the words in a part label */ public static final String PART_LABEL_SEPERATOR = "_"; public static final String PART_COMMON_LABEL = "common"; @@ -66,6 +66,20 @@ public interface ServiceContext { */ public String getServiceName(); + /** + * getDocumentType returns the name of the (primary) DocumentType for this service + * The value defaults to the Service Name, unless overridden with setDocumentType(); + * @return service name + */ + public String getDocumentType(); + + /** + * setDocumentType sets the name of the Document Type for this service + * The value defaults to the Service Name. + * @return service name + */ + public void setDocumentType(String docType); + /** * getQualifiedServiceName returns tenant id qualified service name * @return tenant qualified service name 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 index 03a6d3d44..15a037cd8 100644 --- 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 @@ -43,6 +43,7 @@ public abstract class AbstractDocumentHandler private final Logger logger = LoggerFactory.getLogger(AbstractDocumentHandler.class); private Map properties = new HashMap(); + private DocumentFilter docFilter = new DocumentFilter(); private ServiceContext serviceContext; public AbstractDocumentHandler() { @@ -74,6 +75,22 @@ public abstract class AbstractDocumentHandler this.properties = properties; } + /** + * @return the DocumentFilter + */ + @Override + public DocumentFilter getDocumentFilter() { + return docFilter; + } + + /** + * @param properties the DocumentFilter to set + */ + @Override + public void setDocumentFilter(DocumentFilter docFilter) { + this.docFilter = docFilter; + } + @Override public void prepare(Action action) throws Exception { //no specific action needed diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentFilter.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentFilter.java new file mode 100644 index 000000000..4d65e5876 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentFilter.java @@ -0,0 +1,107 @@ +/** + * 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 + */ +package org.collectionspace.services.common.repository; + +/** + * DocumentFilter bundles simple query filtering parameters. + * It is designed to be used with filtered get and search calls to RepositoryClient. + * The values are set up and stored on a DocumentHandler, and + * fetched by a RepositoryClient when calling filtered get methods. + */ +public class DocumentFilter { + public static final int DEFAULT_PAGE_SIZE_INIT = 40; + public static int defaultPageSize = DEFAULT_PAGE_SIZE_INIT; + protected String whereClause; // Filtering clause. Omit the "WHERE". + protected int startPage; // Pagination offset for list results + protected int pageSize; // Pagination limit for list results + + public DocumentFilter() { + this("", 0, defaultPageSize); // Use empty string for easy concatenation + } + + public DocumentFilter(String whereClause, int startPage, int pageSize) { + this.whereClause = whereClause; + this.startPage = (startPage>0)?startPage:0; + this.pageSize = (pageSize>0)?pageSize:defaultPageSize; + } + + /** + * @return the current default page size for new DocumentFilter instances + */ + public static int getDefaultPageSize() { + return defaultPageSize; + } + + /** + * @param defaultPageSize the working default page size for new DocumentFilter instances + */ + public static void setDefaultPageSize(int defaultPageSize) { + DocumentFilter.defaultPageSize = defaultPageSize; + } + + /** + * @return the WHERE filtering clause + */ + public String getWhereClause() { + return whereClause; + } + + /** + * @param whereClause the filtering clause (do not include "WHERE") + */ + public void setWhereClause(String whereClause) { + this.whereClause = whereClause; + } + + /** + * @return the specified (0-based) page offset + */ + public int getStartPage() { + return startPage; + } + + /** + * @param startPage the (0-based) page offset to use + */ + public void setStartPage(int startPage) { + this.startPage = startPage; + } + + /** + * @return the max number of items to return for list requests + */ + public int getPageSize() { + return pageSize; + } + + /** + * @param pageSize the max number of items to return for list requests + */ + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + /** + * @return the offset computed from the startPage and the pageSize + */ + public int getOffset() { + return pageSize*startPage; + } + + +} 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 50774375a..31aa51442 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 @@ -199,6 +199,19 @@ public interface DocumentHandler { */ public void setProperties(Map properties); + /** + * getDocumentFilter + * @return + */ + public DocumentFilter getDocumentFilter(); + + /** + * setDocumentFilter provides means to the CollectionSpace service resource to + * set up DocumentFilter values before invoking any request via the client. + * @param docFilter + */ + public void setDocumentFilter(DocumentFilter docFilter); + /** * getCommonPart provides the common part of a CS object. * @return common part of CS object 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 f186d2743..1e70ddbf8 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 @@ -67,7 +67,7 @@ public interface RepositoryClient { void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; /** - * getAll get all documents for an entity entity service from the Document repository + * getAll get all documents for an entity service from the Document 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 DocumentNotFoundException if workspace not found @@ -75,6 +75,16 @@ public interface RepositoryClient { */ void getAll(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + /** + * getFiltered get all documents for an entity service from the Document repository, + * given filter parameters specified by the handler. + * @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 getFiltered(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + /** * update given document in the Document repository * @param ctx service context under which this method is invoked 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 d48d06ae0..c03eabaa9 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 @@ -19,12 +19,14 @@ package org.collectionspace.services.nuxeo.client.java; import java.util.UUID; -import org.collectionspace.services.common.repository.RepositoryClient; + 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; import org.collectionspace.services.common.repository.DocumentException; +import org.collectionspace.services.common.repository.DocumentFilter; +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.DocumentNotFoundException; +import org.collectionspace.services.common.repository.RepositoryClient; import org.collectionspace.services.common.repository.DocumentHandler.Action; import org.collectionspace.services.nuxeo.util.NuxeoUtils; import org.nuxeo.common.utils.IdUtils; @@ -220,6 +222,66 @@ public class RepositoryJavaClient implements RepositoryClient { } } } + + /** + * getFiltered get all documents for an entity service from the Document repository, + * given filter parameters specified by the handler. + * @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 + */ + public void getFiltered(ServiceContext ctx, DocumentHandler handler) + throws DocumentNotFoundException, DocumentException { + if (handler == null) { + throw new IllegalArgumentException( + "RemoteRepositoryClient.getFiltered: handler is missing"); + } + DocumentFilter docFilter = handler.getDocumentFilter(); + if (docFilter == null) { + throw new IllegalArgumentException( + "RemoteRepositoryClient.getFiltered: handler has no Filter specified"); + } + String docType = ctx.getDocumentType(); + if (docType == null) { + throw new DocumentNotFoundException( + "Unable to find DocumentType for service " + ctx.getServiceName()); + } + RepositoryInstance repoSession = null; + try { + handler.prepare(Action.GET_ALL); + repoSession = getRepositorySession(); + StringBuilder query = new StringBuilder("SELECT * FROM "); + query.append(docType); + String where = docFilter.getWhereClause(); + if((null!=where)&&(where.length()>0)) + query.append(" WHERE "+where); + if(docFilter.getOffset()>0) + query.append(" OFFSET "+docFilter.getOffset()); + if(docFilter.getPageSize()>0) + query.append(" LIMIT "+docFilter.getPageSize()); + DocumentModelList docList = repoSession.query(query.toString()); + //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); + } + } + } + + /** * update given document in the Nuxeo repository diff --git a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/layouts-contrib.xml b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/layouts-contrib.xml index 87fa5ccb5..9d65eda57 100644 --- a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/layouts-contrib.xml +++ b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/layouts-contrib.xml @@ -11,12 +11,13 @@ displayName + refName vocabType - + true @@ -27,6 +28,19 @@ + + + + + true + + refName + + + dataInputText + + + @@ -51,12 +65,13 @@ displayName + refName inVocabulary - + true @@ -67,6 +82,19 @@ + + + + + true + + refName + + + dataInputText + + + diff --git a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularies_common.xsd b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularies_common.xsd index 6cb8986a6..9e646713f 100644 --- a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularies_common.xsd +++ b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularies_common.xsd @@ -24,6 +24,7 @@ + diff --git a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularyitems_common.xsd b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularyitems_common.xsd index 3720b9b0c..772b0b432 100644 --- a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularyitems_common.xsd +++ b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/schemas/vocabularyitems_common.xsd @@ -7,8 +7,8 @@ Part : Common Used for: Nuxeo EP core document type - $LastChangedRevision$ - $LastChangedDate$ + $LastChangedRevision: 860 $ + $LastChangedDate: 2009-10-14 14:48:05 -0700 (Wed, 14 Oct 2009) $ --> + diff --git a/services/vocabulary/client/src/main/java/org/collectionspace/services/client/importer/VocabularyBaseImport.java b/services/vocabulary/client/src/main/java/org/collectionspace/services/client/importer/VocabularyBaseImport.java index 9befe6b01..bcc5f5fe4 100644 --- a/services/vocabulary/client/src/main/java/org/collectionspace/services/client/importer/VocabularyBaseImport.java +++ b/services/vocabulary/client/src/main/java/org/collectionspace/services/client/importer/VocabularyBaseImport.java @@ -60,74 +60,77 @@ public class VocabularyBaseImport { public void createEnumeration(String vocabName, List enumValues ) { - // Expected status code: 201 Created - int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); - // Type of service request being tested - ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; - - if(logger.isDebugEnabled()){ - logger.debug("Import: Create vocabulary: \"" + vocabName +"\""); - } - MultipartOutput multipart = createVocabularyInstance(vocabName, "enum"); - ClientResponse res = client.create(multipart); - - int statusCode = res.getStatus(); - - if(!REQUEST_TYPE.isValidStatusCode(statusCode)) { - throw new RuntimeException("Could not create enumeration: \""+vocabName - +"\" "+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - } - if(statusCode != EXPECTED_STATUS_CODE) { - throw new RuntimeException("Unexpected Status when creating enumeration: \"" - +vocabName +"\", Status:"+ statusCode); - } - - // Store the ID returned from this create operation - // for additional tests below. - String newVocabId = extractId(res); - if(logger.isDebugEnabled()){ - logger.debug("Import: Created vocabulary: \"" + vocabName +"\" ID:" - +newVocabId ); - } - for(String itemName : enumValues){ - createItemInVocab(newVocabId, vocabName, itemName); - } + // Expected status code: 201 Created + int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); + // Type of service request being tested + ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; + + if(logger.isDebugEnabled()){ + logger.debug("Import: Create vocabulary: \"" + vocabName +"\""); + } + MultipartOutput multipart = createVocabularyInstance(vocabName, + createRefName(vocabName), "enum"); + ClientResponse res = client.create(multipart); + + int statusCode = res.getStatus(); + + if(!REQUEST_TYPE.isValidStatusCode(statusCode)) { + throw new RuntimeException("Could not create enumeration: \""+vocabName + +"\" "+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + } + if(statusCode != EXPECTED_STATUS_CODE) { + throw new RuntimeException("Unexpected Status when creating enumeration: \"" + +vocabName +"\", Status:"+ statusCode); + } + + // Store the ID returned from this create operation + // for additional tests below. + String newVocabId = extractId(res); + if(logger.isDebugEnabled()){ + logger.debug("Import: Created vocabulary: \"" + vocabName +"\" ID:" + +newVocabId ); + } + for(String itemName : enumValues){ + createItemInVocab(newVocabId, vocabName, itemName, createRefName(itemName)); + } } - private String createItemInVocab(String vcsid, String vocabName, String itemName) { - // Expected status code: 201 Created - int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); - // Type of service request being tested - ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; - - if(logger.isDebugEnabled()){ - logger.debug("Import: Create Item: \""+itemName+"\" in vocabulary: \"" + vocabName +"\""); - } - MultipartOutput multipart = createVocabularyItemInstance(vcsid, itemName); - ClientResponse res = client.createItem(vcsid, multipart); - - int statusCode = res.getStatus(); - - if(!REQUEST_TYPE.isValidStatusCode(statusCode)) { - throw new RuntimeException("Could not create Item: \""+itemName - +"\" in vocabulary: \"" + vocabName - +"\" "+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - } - if(statusCode != EXPECTED_STATUS_CODE) { - throw new RuntimeException("Unexpected Status when creating Item: \""+itemName - +"\" in vocabulary: \"" + vocabName +"\", Status:"+ statusCode); - } - - return extractId(res); + private String createItemInVocab(String vcsid, String vocabName, String itemName, String refName) { + // Expected status code: 201 Created + int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); + // Type of service request being tested + ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; + + if(logger.isDebugEnabled()){ + logger.debug("Import: Create Item: \""+itemName+"\" in vocabulary: \"" + vocabName +"\""); + } + MultipartOutput multipart = createVocabularyItemInstance(vcsid, itemName, refName); + ClientResponse res = client.createItem(vcsid, multipart); + + int statusCode = res.getStatus(); + + if(!REQUEST_TYPE.isValidStatusCode(statusCode)) { + throw new RuntimeException("Could not create Item: \""+itemName + +"\" in vocabulary: \"" + vocabName + +"\" "+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + } + if(statusCode != EXPECTED_STATUS_CODE) { + throw new RuntimeException("Unexpected Status when creating Item: \""+itemName + +"\" in vocabulary: \"" + vocabName +"\", Status:"+ statusCode); + } + + return extractId(res); } // --------------------------------------------------------------- // Utility methods used by tests above // --------------------------------------------------------------- - private MultipartOutput createVocabularyInstance(String displayName, String vocabType) { + private MultipartOutput createVocabularyInstance( + String displayName, String refName, String vocabType) { VocabulariesCommon vocabulary = new VocabulariesCommon(); vocabulary.setDisplayName(displayName); + vocabulary.setRefName(refName); vocabulary.setVocabType(vocabType); MultipartOutput multipart = new MultipartOutput(); OutputPart commonPart = multipart.addPart(vocabulary, MediaType.APPLICATION_XML_TYPE); @@ -141,10 +144,12 @@ public class VocabularyBaseImport { return multipart; } - private MultipartOutput createVocabularyItemInstance(String inVocabulary, String displayName) { + private MultipartOutput createVocabularyItemInstance( + String inVocabulary, String displayName, String refName) { VocabularyitemsCommon vocabularyItem = new VocabularyitemsCommon(); vocabularyItem.setInVocabulary(inVocabulary); vocabularyItem.setDisplayName(displayName); + vocabularyItem.setRefName(refName); MultipartOutput multipart = new MultipartOutput(); OutputPart commonPart = multipart.addPart(vocabularyItem, MediaType.APPLICATION_XML_TYPE); commonPart.getHeaders().add("label", client.getItemCommonPartName()); @@ -187,6 +192,10 @@ public class VocabularyBaseImport { } return id; } + + protected String createRefName(String displayName) { + return displayName.replaceAll("\\W", ""); + } public static void main(String[] args) { diff --git a/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java b/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java index e4ed30d63..6da36afc0 100644 --- a/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java +++ b/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java @@ -58,7 +58,12 @@ public class VocabularyServiceTest extends AbstractServiceTest { final String SERVICE_PATH_COMPONENT = "vocabularies"; final String ITEM_SERVICE_PATH_COMPONENT = "items"; private String knownResourceId = null; + private String knownResourceRefName = null; private String knownItemResourceId = null; + + protected String createRefName(String displayName) { + return displayName.replaceAll("\\W", ""); + } // --------------------------------------------------------------- // CRUD tests : CREATE tests @@ -75,7 +80,11 @@ public class VocabularyServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. String identifier = createIdentifier(); - MultipartOutput multipart = createVocabularyInstance(identifier); + String displayName = "displayName-" + identifier; + String refName = createRefName(displayName); + String typeName = "vocabType-" + identifier; + MultipartOutput multipart = + createVocabularyInstance(displayName, refName, typeName); ClientResponse res = client.create(multipart); int statusCode = res.getStatus(); @@ -95,6 +104,7 @@ public class VocabularyServiceTest extends AbstractServiceTest { // Store the ID returned from this create operation // for additional tests below. knownResourceId = extractId(res); + knownResourceRefName = refName; if(logger.isDebugEnabled()){ logger.debug("create: knownResourceId=" + knownResourceId); } @@ -120,7 +130,8 @@ public class VocabularyServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. String identifier = createIdentifier(); - MultipartOutput multipart = createVocabularyItemInstance(vcsid, identifier); + String refName = createRefName(identifier); + MultipartOutput multipart = createVocabularyItemInstance(vcsid, identifier, refName); ClientResponse res = client.createItem(vcsid, multipart); int statusCode = res.getStatus(); @@ -279,6 +290,38 @@ public class VocabularyServiceTest extends AbstractServiceTest { } } + /* + @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, + dependsOnMethods = {"read"}) + public void readByName(String testName) throws Exception { + + // Perform setup. + setupRead(); + + // Submit the request to the service and store the response. + ClientResponse res = client.read(knownResourceId); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + if(logger.isDebugEnabled()){ + logger.debug(testName + ": status = " + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(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(); + VocabulariesCommon vocabulary = (VocabulariesCommon) extractPart(input, + client.getCommonPartName(), VocabulariesCommon.class); + Assert.assertNotNull(vocabulary); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + */ + @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, dependsOnMethods = {"createItem", "read"}) public void readItem(String testName) throws Exception { @@ -704,7 +747,8 @@ public class VocabularyServiceTest extends AbstractServiceTest { // The only relevant ID may be the one used in update(), below. // The only relevant ID may be the one used in update(), below. - MultipartOutput multipart = createVocabularyItemInstance(knownResourceId, NON_EXISTENT_ID); + MultipartOutput multipart = createVocabularyItemInstance( + knownResourceId, NON_EXISTENT_ID, createRefName(NON_EXISTENT_ID)); ClientResponse res = client.updateItem(knownResourceId, NON_EXISTENT_ID, multipart); int statusCode = res.getStatus(); @@ -898,14 +942,19 @@ public class VocabularyServiceTest extends AbstractServiceTest { } private MultipartOutput createVocabularyInstance(String identifier) { + String displayName = "displayName-" + identifier; + String refName = createRefName(displayName); + String typeName = "vocabType-" + identifier; return createVocabularyInstance( - "displayName-" + identifier, - "vocabType-" + identifier); + displayName, refName,typeName ); } - private MultipartOutput createVocabularyInstance(String displayName, String vocabType) { + private MultipartOutput createVocabularyInstance( + String displayName, String refName, String vocabType) { VocabulariesCommon vocabulary = new VocabulariesCommon(); vocabulary.setDisplayName(displayName); + if(refName!=null) + vocabulary.setRefName(refName); vocabulary.setVocabType(vocabType); MultipartOutput multipart = new MultipartOutput(); OutputPart commonPart = multipart.addPart(vocabulary, MediaType.APPLICATION_XML_TYPE); @@ -919,10 +968,12 @@ public class VocabularyServiceTest extends AbstractServiceTest { } private MultipartOutput createVocabularyItemInstance(String inVocabulary, - String displayName) { + String displayName, String refName) { VocabularyitemsCommon vocabularyItem = new VocabularyitemsCommon(); vocabularyItem.setInVocabulary(inVocabulary); vocabularyItem.setDisplayName(displayName); + if(refName!=null) + vocabularyItem.setRefName(refName); MultipartOutput multipart = new MultipartOutput(); OutputPart commonPart = multipart.addPart(vocabularyItem, MediaType.APPLICATION_XML_TYPE); diff --git a/services/vocabulary/jaxb/src/main/resources/vocabulary_common.xsd b/services/vocabulary/jaxb/src/main/resources/vocabulary_common.xsd index 90144b6ca..539f589cc 100644 --- a/services/vocabulary/jaxb/src/main/resources/vocabulary_common.xsd +++ b/services/vocabulary/jaxb/src/main/resources/vocabulary_common.xsd @@ -34,6 +34,7 @@ + diff --git a/services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd b/services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd index 9b62ae270..cd2a95ee6 100644 --- a/services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd +++ b/services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd @@ -22,6 +22,7 @@ + diff --git a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java index f0ea4e94b..a210df869 100644 --- a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java +++ b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java @@ -23,6 +23,9 @@ */ package org.collectionspace.services.vocabulary; +import java.util.List; +import java.util.Map; + import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -31,8 +34,10 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; @@ -42,6 +47,7 @@ import org.collectionspace.services.common.ClientType; import org.collectionspace.services.common.ServiceMain; import org.collectionspace.services.common.context.RemoteServiceContext; import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.repository.DocumentFilter; import org.collectionspace.services.common.repository.DocumentHandler; import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.vocabulary.nuxeo.VocabularyHandlerFactory; @@ -50,6 +56,8 @@ import org.collectionspace.services.vocabulary.nuxeo.VocabularyItemHandlerFactor import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.util.HttpResponseCodes; +import org.nuxeo.ecm.core.api.repository.RepositoryInstance; +import org.nuxeo.ecm.core.client.NuxeoClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -139,23 +147,23 @@ public class VocabularyResource extends AbstractCollectionSpaceResource { @GET @Path("{csid}") - public MultipartOutput getVocabulary( - @PathParam("csid") String csid) { - if(logger.isDebugEnabled()){ - logger.debug("getVocabulary with csid=" + csid); - } - if(csid == null || "".equals(csid)){ + public MultipartOutput getVocabulary(@PathParam("csid") String csid) { + String idValue = null; + if(csid == null){ logger.error("getVocabulary: missing csid!"); Response response = Response.status(Response.Status.BAD_REQUEST).entity( "get failed on Vocabulary csid=" + csid).type( "text/plain").build(); throw new WebApplicationException(response); } + if(logger.isDebugEnabled()){ + logger.debug("getVocabulary with path(id)=" + csid); + } MultipartOutput result = null; try{ RemoteServiceContext ctx = createServiceContext(null); DocumentHandler handler = createDocumentHandler(ctx); - getRepositoryClient(ctx).get(ctx, csid, handler); + getRepositoryClient(ctx).get(ctx, csid, handler); result = ctx.getOutput(); }catch(DocumentNotFoundException dnfe){ if(logger.isDebugEnabled()){ @@ -189,7 +197,16 @@ public class VocabularyResource extends AbstractCollectionSpaceResource { try{ RemoteServiceContext ctx = createServiceContext(null); DocumentHandler handler = createDocumentHandler(ctx); - getRepositoryClient(ctx).getAll(ctx, handler); + MultivaluedMap queryParams = ui.getQueryParameters(); + if(queryParams.size()>0) { + String nameQ = queryParams.getFirst("name"); + if(nameQ!= null) { + DocumentFilter myFilter = new DocumentFilter( + "vocabularies_common:refName='"+nameQ+"'", 0, 0); + handler.setDocumentFilter(myFilter); + } + } + getRepositoryClient(ctx).getFiltered(ctx, handler); vocabularyObjectList = (VocabulariesCommonList) handler.getCommonPartList(); }catch(Exception e){ if(logger.isDebugEnabled()){ @@ -361,14 +378,34 @@ public class VocabularyResource extends AbstractCollectionSpaceResource { @PathParam("csid") String parentcsid, @Context UriInfo ui) { VocabularyitemsCommonList vocabularyItemObjectList = new VocabularyitemsCommonList(); + RepositoryInstance repoSession = null; + NuxeoClient client = null; try{ - // Note that we have to create the service context for the Items, not the main service + // Note that docType defaults to the ServiceName, so we're fine with that. RemoteServiceContext ctx = createServiceContext(null, getItemServiceName()); DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid); - // HACK This should be a search with the parentcsid. The - // handler.getCommonPartList method will filter these for us, - // which is really silly, but works for now. - getRepositoryClient(ctx).getAll(ctx, handler); + /* + // Note that we replace the getAll() call with a basic search on the parent vocab + handler.prepare(Action.GET_ALL); + client = NuxeoConnector.getInstance().getClient(); + repoSession = client.openRepository(); + if (logger.isDebugEnabled()) { + logger.debug("getVocabularyItemList() repository root: " + repoSession.getRootDocument()); + } + DocumentModelList docList = + repoSession.query("SELECT * FROM Vocabularyitem WHERE vocabularyitems_common:inVocabulary='" + +parentcsid+"'"); + //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); + */ + DocumentFilter myFilter = new DocumentFilter( + "vocabularyitems_common:inVocabulary='"+parentcsid+"'", 0, 0); + handler.setDocumentFilter(myFilter); + getRepositoryClient(ctx).getFiltered(ctx, handler); vocabularyItemObjectList = (VocabularyitemsCommonList) handler.getCommonPartList(); }catch(Exception e){ if(logger.isDebugEnabled()){ @@ -377,6 +414,16 @@ public class VocabularyResource extends AbstractCollectionSpaceResource { Response response = Response.status( Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build(); throw new WebApplicationException(response); + } finally { + if(repoSession != null) { + try { + // 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 + } + } } return vocabularyItemObjectList; } diff --git a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java index c5be87a31..371ea7832 100644 --- a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java +++ b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java @@ -135,10 +135,10 @@ public class VocabularyItemDocumentModelHandler Iterator iter = docList.iterator(); while(iter.hasNext()){ DocumentModel docModel = iter.next(); - String parentVocab = (String)docModel.getProperty(getServiceContext().getCommonPartLabel("vocabularyItems"), - VocabularyItemJAXBSchema.IN_VOCABULARY); - if( !inVocabulary.equals(parentVocab)) - continue; + //String parentVocab = (String)docModel.getProperty(getServiceContext().getCommonPartLabel("vocabularyItems"), + // VocabularyItemJAXBSchema.IN_VOCABULARY); + //if( !inVocabulary.equals(parentVocab)) + // continue; VocabularyitemListItem ilistItem = new VocabularyitemListItem(); ilistItem.setDisplayName((String) docModel.getProperty(getServiceContext().getCommonPartLabel("vocabularyItems"), VocabularyItemJAXBSchema.DISPLAY_NAME)); -- 2.47.3