From: Patrick Schmitz Date: Tue, 2 Mar 2010 00:02:05 +0000 (+0000) Subject: CSPACE-590, CSPACE-852. Added support to get PersonAuthority by name, prototyping... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=24d318615201296dc9b7703bbe9063a5bfcb1364;p=tmp%2Fjakarta-migration.git CSPACE-590, CSPACE-852. Added support to get PersonAuthority by name, prototyping basic facility. Required changes to the StorageClient class-tree. Added tests for same. Still have to work out how to get sub-resources (trickier). --- diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/StorageClient.java b/services/common/src/main/java/org/collectionspace/services/common/storage/StorageClient.java index 3e34f29c8..8142c0bf1 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/StorageClient.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/StorageClient.java @@ -60,6 +60,16 @@ public interface StorageClient { */ void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + /** + * get entity from the persistence store, using the docFilter params. + * @param ctx service context under which this method is invoked + * @param handler should be used by the caller to provide and transform the entity. + * Handler must have a docFilter set to return a single item. + * @throws DocumentNotFoundException if entity not found + * @throws DocumentException + */ + void get(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + /** * Gets the. * diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java index fbb34cc24..6568653fb 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java @@ -519,4 +519,10 @@ public class JpaStorageClientImpl implements StorageClient { return (String) o; } + + @Override + public void get(ServiceContext ctx, DocumentHandler handler) + throws DocumentNotFoundException, DocumentException { + throw new UnsupportedOperationException(); + } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/vocabulary/RefNameUtils.java b/services/common/src/main/java/org/collectionspace/services/common/vocabulary/RefNameUtils.java index 59368cac6..71ae5631f 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/vocabulary/RefNameUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/vocabulary/RefNameUtils.java @@ -42,7 +42,10 @@ public class RefNameUtils { private final Logger logger = LoggerFactory.getLogger(RefNameUtils.class); - private static final String URN_PREFIX = "urn:cspace:"; + public static final String URN_PREFIX = "urn:cspace:"; + public static final int URN_PREFIX_LEN = 11; + public static final String URN_NAME_PREFIX = "urn:cspace:name("; + public static final int URN_NAME_PREFIX_LEN = 16; // FIXME Should not be hard-coded private static final String ITEMS_REGEX = "item|person|organization"; // In a list of tokens, these are indices for each part @@ -57,7 +60,6 @@ public class RefNameUtils { private static final int INSTANCE_DISPLAYNAME_TOKEN = 2;// optional displayName suffix private static final int INSTANCE_TOKENS_MIN = 2; private static final int INSTANCE_TOKENS_MAX = 3; - private static final int prefixLen = 11; private static final String SEPARATOR = ":"; public static class AuthorityInfo { @@ -185,14 +187,14 @@ public class RefNameUtils { throws Exception { if(refName==null || !refName.startsWith(URN_PREFIX)) throw new RuntimeException( "Null or invalid refName syntax"); - return new AuthorityInfo(refName.substring(prefixLen).split(SEPARATOR)); + return new AuthorityInfo(refName.substring(URN_PREFIX_LEN).split(SEPARATOR)); } public static AuthorityTermInfo parseAuthorityTermInfo(String refName) throws Exception { if(refName==null || !refName.startsWith(URN_PREFIX)) throw new RuntimeException( "Null or invalid refName syntax"); - return new AuthorityTermInfo(refName.substring(prefixLen).split(SEPARATOR)); + return new AuthorityTermInfo(refName.substring(URN_PREFIX_LEN).split(SEPARATOR)); } public static String implodeStringArray(String tokens[], String separator) { diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java index a2d05fa2c..fb0c9287e 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java @@ -177,6 +177,80 @@ public class RepositoryJavaClientImpl implements RepositoryClient { } } + /** + * get document from the Nuxeo repository, using the docFilter params. + * @param ctx service context under which this method is invoked + * @param handler + * should be used by the caller to provide and transform the + * document. Handler must have a docFilter set to return a single item. + * @throws DocumentException + */ + @Override + public void get(ServiceContext ctx, DocumentHandler handler) + throws DocumentNotFoundException, DocumentException { + + if (handler == null) { + throw new IllegalArgumentException( + "RepositoryJavaClient.get: handler is missing"); + } + DocumentFilter docFilter = handler.getDocumentFilter(); + if (docFilter == null) { + throw new IllegalArgumentException( + "RepositoryJavaClient.get: handler has no Filter specified"); + } + if(docFilter.getPageSize()!= 1) { + logger.warn("RepositoryJavaClient.get: forcing docFilter pagesize to 1."); + } + String docType = ctx.getDocumentType(); + if (docType == null) { + throw new DocumentNotFoundException( + "Unable to find DocumentType for service " + ctx.getServiceName()); + } + String domain = ctx.getRepositoryDomainName(); + if (domain == null) { + throw new DocumentNotFoundException( + "Unable to find Domain for service " + ctx.getServiceName()); + } + RepositoryInstance repoSession = null; + + try { + handler.prepare(Action.GET); + repoSession = getRepositorySession(); + + DocumentModelList docList = null; + // force limit to 1, and ignore totalSize + String query = buildNXQLQuery(docType, docFilter.getWhereClause(), domain ); + docList = repoSession.query( query, null, 1, 0, false); + if(docList.size()!=1) { + throw new DocumentNotFoundException("No document found matching filter params."); + } + DocumentModel doc = docList.get(0); + + if (logger.isDebugEnabled()) { + logger.debug("Executed NXQL query: " + query); + } + + //set reposession to handle the document + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentWrapper wrapDoc = new DocumentWrapperImpl(doc); + handler.handle(Action.GET, wrapDoc); + handler.complete(Action.GET, wrapDoc); + } catch (IllegalArgumentException iae) { + throw iae; + } catch (DocumentException de) { + throw de; + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + } finally { + if (repoSession != null) { + releaseRepositorySession(repoSession); + } + } + } + /** * get wrapped documentModel from the Nuxeo repository * @param ctx service context under which this method is invoked @@ -343,25 +417,16 @@ public class RepositoryJavaClientImpl implements RepositoryClient { try { handler.prepare(Action.GET_ALL); repoSession = getRepositorySession(); - StringBuilder query = new StringBuilder("SELECT * FROM "); - query.append(docType); - String where = docFilter.getWhereClause(); - // TODO This is a slow method for tenant-filter - // We should make this a property that is indexed. - query.append(" WHERE ecm:path STARTSWITH '/" + domain + "'"); - if ((null != where) && (where.length() > 0)) { - // Due to an apparent bug/issue in how Nuxeo translates the NXQL query string - // into SQL, we need to parenthesize our 'where' clause - query.append(" AND " + "(" + where +")" + "AND ecm:isProxy = 0"); - } DocumentModelList docList = null; + String query = buildNXQLQuery(docType, docFilter.getWhereClause(), domain ); + // If we have limit and/or offset, then pass true to get totalSize // in returned DocumentModelList. if ((docFilter.getOffset() > 0) || (docFilter.getPageSize() > 0)) { - docList = repoSession.query(query.toString(), null, + docList = repoSession.query(query, null, docFilter.getPageSize(), docFilter.getOffset(), true); } else { - docList = repoSession.query(query.toString()); + docList = repoSession.query(query); } if (logger.isDebugEnabled()) { @@ -543,6 +608,20 @@ public class RepositoryJavaClientImpl implements RepositoryClient { } return workspaceId; } + + private final String buildNXQLQuery(String docType, String where, String domain ) { + StringBuilder query = new StringBuilder("SELECT * FROM "); + query.append(docType); + // TODO This is a slow method for tenant-filter + // We should make this a property that is indexed. + query.append(" WHERE ecm:path STARTSWITH '/" + domain + "'"); + if ((null != where) && (where.length() > 0)) { + // Due to an apparent bug/issue in how Nuxeo translates the NXQL query string + // into SQL, we need to parenthesize our 'where' clause + query.append(" AND " + "(" + where +")" + "AND ecm:isProxy = 0"); + } + return query.toString(); + } private RepositoryInstance getRepositorySession() throws Exception { // FIXME: is it possible to reuse repository session? diff --git a/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityClient.java b/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityClient.java index 65c7d28a9..fecd59d42 100644 --- a/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityClient.java +++ b/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityClient.java @@ -92,6 +92,15 @@ public class PersonAuthorityClient extends AbstractServiceClientImpl { return personAuthorityProxy.read(csid); } + /** + * @param name + * @return + * @see org.collectionspace.services.client.PersonAuthorityProxy#readByName(java.lang.String) + */ + public ClientResponse readByName(String name) { + return personAuthorityProxy.readByName(name); + } + /** * @param personAuthority * @return diff --git a/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityProxy.java b/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityProxy.java index 3f5f82759..3a25ba8a1 100644 --- a/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityProxy.java +++ b/services/person/client/src/main/java/org/collectionspace/services/client/PersonAuthorityProxy.java @@ -39,6 +39,11 @@ public interface PersonAuthorityProxy { @Path("/{csid}") ClientResponse read(@PathParam("csid") String csid); + //(R)ead by name + @GET + @Path("/urn:cspace:name({name})") + ClientResponse readByName(@PathParam("name") String name); + //(U)pdate @PUT @Path("/{csid}") diff --git a/services/person/client/src/test/java/org/collectionspace/services/client/test/PersonAuthorityServiceTest.java b/services/person/client/src/test/java/org/collectionspace/services/client/test/PersonAuthorityServiceTest.java index 8c25b8965..31f726b21 100644 --- a/services/person/client/src/test/java/org/collectionspace/services/client/test/PersonAuthorityServiceTest.java +++ b/services/person/client/src/test/java/org/collectionspace/services/client/test/PersonAuthorityServiceTest.java @@ -75,6 +75,7 @@ public class PersonAuthorityServiceTest extends AbstractServiceTestImpl { final String TEST_DEATH_DATE = "June 11, 1979"; private String knownResourceId = null; + private String knownResourceDisplayName = null; private String knownResourceRefName = null; private String knownItemResourceId = null; private String knownContactResourceId = null; @@ -132,6 +133,7 @@ public class PersonAuthorityServiceTest extends AbstractServiceTestImpl { // for additional tests below. if (knownResourceId == null){ knownResourceId = newID; + knownResourceDisplayName = displayName; if (logger.isDebugEnabled()) { logger.debug(testName + ": knownResourceId=" + knownResourceId); } @@ -417,6 +419,36 @@ public class PersonAuthorityServiceTest extends AbstractServiceTestImpl { } } + @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class, + groups = {"read"}, dependsOnGroups = {"create"}) + public void readByName(String testName) throws Exception { + + // Perform setup. + setupRead(); + + // Submit the request to the service and store the response. + ClientResponse res = client.readByName(knownResourceDisplayName); + 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(); + PersonauthoritiesCommon personAuthority = (PersonauthoritiesCommon) extractPart(input, + client.getCommonPartName(), PersonauthoritiesCommon.class); + Assert.assertNotNull(personAuthority); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + /* @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, groups = {"read"}, dependsOnMethods = {"read"}) diff --git a/services/person/jaxb/src/main/java/org/collectionspace/services/PersonAuthorityJAXBSchema.java b/services/person/jaxb/src/main/java/org/collectionspace/services/PersonAuthorityJAXBSchema.java index cef5d5e1a..b80986b82 100644 --- a/services/person/jaxb/src/main/java/org/collectionspace/services/PersonAuthorityJAXBSchema.java +++ b/services/person/jaxb/src/main/java/org/collectionspace/services/PersonAuthorityJAXBSchema.java @@ -8,6 +8,7 @@ package org.collectionspace.services; * */ public interface PersonAuthorityJAXBSchema { + final static String PERSONAUTHORITIES_COMMON = "personauthorities_common"; final static String DISPLAY_NAME = "displayName"; final static String REF_NAME = "refName"; final static String VOCAB_TYPE = "vocabType"; diff --git a/services/person/service/src/main/java/org/collectionspace/services/person/PersonAuthorityResource.java b/services/person/service/src/main/java/org/collectionspace/services/person/PersonAuthorityResource.java index d98f2748e..26e09c57a 100644 --- a/services/person/service/src/main/java/org/collectionspace/services/person/PersonAuthorityResource.java +++ b/services/person/service/src/main/java/org/collectionspace/services/person/PersonAuthorityResource.java @@ -41,6 +41,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; +import org.collectionspace.services.PersonAuthorityJAXBSchema; import org.collectionspace.services.PersonJAXBSchema; import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl; import org.collectionspace.services.common.ClientType; @@ -53,6 +54,7 @@ import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentHandler; import org.collectionspace.services.common.document.DocumentNotFoundException; import org.collectionspace.services.common.security.UnauthorizedException; +import org.collectionspace.services.common.vocabulary.RefNameUtils; import org.collectionspace.services.common.query.IQueryManager; import org.collectionspace.services.contact.ContactResource; import org.collectionspace.services.contact.ContactsCommon; @@ -178,10 +180,69 @@ public class PersonAuthorityResource extends AbstractCollectionSpaceResourceImpl } } + @GET + @Path("urn:cspace:name({specifier})") + public MultipartOutput getPersonAuthorityByName(@PathParam("specifier") String specifier) { + String idValue = null; + if (specifier == null) { + logger.error("getPersonAuthority: missing name!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "get failed on PersonAuthority (missing specifier)").type( + "text/plain").build(); + throw new WebApplicationException(response); + } + String whereClause = + PersonAuthorityJAXBSchema.PERSONAUTHORITIES_COMMON+ + ":"+PersonAuthorityJAXBSchema.DISPLAY_NAME+ + "='"+specifier+"'"; + // We only get a single doc - if there are multiple, + // it is an error in use. + + if (logger.isDebugEnabled()) { + logger.debug("getPersonAuthority with name=" + specifier); + } + MultipartOutput result = null; + try { + ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getServiceName()); + DocumentHandler handler = createDocumentHandler(ctx); + DocumentFilter myFilter = new DocumentFilter(whereClause, 0, 1); + handler.setDocumentFilter(myFilter); + getRepositoryClient(ctx).get(ctx, handler); + result = (MultipartOutput) ctx.getOutput(); + } catch (UnauthorizedException ue) { + Response response = Response.status( + Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build(); + throw new WebApplicationException(response); + } catch (DocumentNotFoundException dnfe) { + if (logger.isDebugEnabled()) { + logger.debug("getPersonAuthority", dnfe); + } + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Get failed on PersonAuthority spec=" + specifier).type( + "text/plain").build(); + throw new WebApplicationException(response); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("getPersonAuthority", e); + } + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + if (result == null) { + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Get failed, the requested PersonAuthority spec:" + specifier + ": was not found.").type( + "text/plain").build(); + throw new WebApplicationException(response); + } + return result; + } + @GET @Path("{csid}") public MultipartOutput getPersonAuthority(@PathParam("csid") String csid) { String idValue = null; + DocumentFilter myFilter = null; if (csid == null) { logger.error("getPersonAuthority: missing csid!"); Response response = Response.status(Response.Status.BAD_REQUEST).entity( @@ -191,7 +252,7 @@ public class PersonAuthorityResource extends AbstractCollectionSpaceResourceImpl } if (logger.isDebugEnabled()) { logger.debug("getPersonAuthority with path(id)=" + csid); - } + } MultipartOutput result = null; try { ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getServiceName()); @@ -451,8 +512,7 @@ public class PersonAuthorityResource extends AbstractCollectionSpaceResourceImpl // Add the where clause "persons_common:inAuthority='" + parentcsid + "'" myFilter.setWhereClause(PersonJAXBSchema.PERSONS_COMMON + ":" + - PersonJAXBSchema.IN_AUTHORITY + - "='" + parentcsid + "'" + "AND ecm:isProxy = 0"); + PersonJAXBSchema.IN_AUTHORITY + "='" + parentcsid + "'"); // AND persons_common:displayName LIKE '%partialTerm%' if (partialTerm != null && !partialTerm.isEmpty()) {