From f592b083e1cae07efd9c677e84cc47e199265d6e Mon Sep 17 00:00:00 2001 From: Richard Millet Date: Fri, 30 Jul 2010 05:37:39 +0000 Subject: [PATCH] CSPACE-2492, CSPACE-2492, CSPACE-2492, CSPACE-2463: Changes to reduce the number of permission/resource tuples -in hopes of simplifying the App->Service interactions. Also contains changes to Relation service to add support for query params for subject=sbj, predicate=prd, object=obj -this replaces paths like /subject, /type, /object. --- README.txt | 2 +- .../test/RelationIntegrationTest.java | 3 +- .../test/PerformanceTest.java | 120 ++++++++-- .../client/test/PermissionServiceTest.java | 5 +- .../importer/AuthorizationGen.java | 46 ++-- .../jaxb/src/main/resources/permissions.xsd | 11 + .../main/resources/db/mysql/authorization.sql | 2 +- .../services/authorization/AuthZ.java | 2 +- .../client/AbstractServiceClientImpl.java | 8 +- .../client/CollectionSpaceClient.java | 8 +- .../services/client/CollectionSpaceProxy.java | 9 +- .../client/test/AbstractServiceTestImpl.java | 2 +- .../CollectionObjectResource.java | 20 ++ services/common/pom.xml | 5 + .../common/document/DocumentUtils.java | 86 ++++--- .../common/security/SecurityInterceptor.java | 211 ++++++++++-------- .../common/security/SecurityUtils.java | 69 ++++++ .../java/RemoteDocumentModelHandlerImpl.java | 3 +- ...RemoteSubItemDocumentModelHandlerImpl.java | 3 +- services/location/jaxb/.classpath | 1 + services/relation/client/pom.xml | 6 + .../services/client/RelationClient.java | 23 +- .../services/client/RelationProxy.java | 22 +- .../relation/NewRelationResource.java | 14 +- 24 files changed, 482 insertions(+), 199 deletions(-) diff --git a/README.txt b/README.txt index cdb9fee3e..b4b25d794 100644 --- a/README.txt +++ b/README.txt @@ -1 +1 @@ -This change should only appear in the trunk. Currently r1624. \ No newline at end of file +This change should only appear in the trunk. Currently r1624. This is another test of the patching mechanism. \ No newline at end of file diff --git a/services/IntegrationTests/src/test/java/org/collectionspace/services/ItegrationTests/test/RelationIntegrationTest.java b/services/IntegrationTests/src/test/java/org/collectionspace/services/ItegrationTests/test/RelationIntegrationTest.java index 99f2e2c2b..3703c5cfe 100644 --- a/services/IntegrationTests/src/test/java/org/collectionspace/services/ItegrationTests/test/RelationIntegrationTest.java +++ b/services/IntegrationTests/src/test/java/org/collectionspace/services/ItegrationTests/test/RelationIntegrationTest.java @@ -133,7 +133,8 @@ public class RelationIntegrationTest extends CollectionSpaceIntegrationTest { // Now try to retrieve the Intake record of the CollectionObject. // String predicate = RelationshipType.COLLECTIONOBJECT_INTAKE.value(); - ClientResponse resultResponse = relationClient.readList_SPO(collectionObjectCsid, + ClientResponse resultResponse = relationClient.readList( + collectionObjectCsid, predicate, intakeCsid); RelationsCommonList relationList = null; diff --git a/services/PerformanceTests/src/test/java/org/collectionspace/services/PerformanceTests/test/PerformanceTest.java b/services/PerformanceTests/src/test/java/org/collectionspace/services/PerformanceTests/test/PerformanceTest.java index c9d682109..c48dc167f 100644 --- a/services/PerformanceTests/src/test/java/org/collectionspace/services/PerformanceTests/test/PerformanceTest.java +++ b/services/PerformanceTests/src/test/java/org/collectionspace/services/PerformanceTests/test/PerformanceTest.java @@ -66,19 +66,20 @@ public class PerformanceTest extends CollectionSpacePerformanceTest { // Get clients for the CollectionSpace services // /** The MA x_ records. */ - private static int MAX_RECORDS = 1; + private static int MAX_RECORDS = 1000; /** * Performance test. */ @Test public void performanceTest() { -// roundTripOverhead(MAX_RECORDS); -// deleteCollectionObjects(); + roundTripOverhead(10); + deleteCollectionObjects(); String[] coList = this.createCollectionObjects(MAX_RECORDS); -// this.searchCollectionObjects(MAX_RECORDS); -// this.deleteCollectionObjects(coList); -// roundTripOverhead(10); + this.searchCollectionObjects(MAX_RECORDS); + this.readCollectionObjects(coList); + this.deleteCollectionObjects(coList); + roundTripOverhead(10); } /** @@ -173,18 +174,8 @@ public class PerformanceTest extends CollectionSpacePerformanceTest { * @return the string */ private String createCollectionObject(CollectionObjectClient collectionObjectClient, - int identifier) { + MultipartOutput multipart) { String result = null; - // - // First create a CollectionObject - // - CollectionobjectsCommon co = new CollectionobjectsCommon(); - fillCollectionObject(co, Integer.toString(identifier)); - - // Next, create a part object - MultipartOutput multipart = new MultipartOutput(); - OutputPart commonPart = multipart.addPart(co, MediaType.APPLICATION_XML_TYPE); - commonPart.getHeaders().add("label", collectionObjectClient.getCommonPartName()); // Make the create call and check the response ClientResponse response = collectionObjectClient.create(multipart); try { @@ -213,15 +204,29 @@ public class PerformanceTest extends CollectionSpacePerformanceTest { public String[] createCollectionObjects(int numberOfObjects) { Random randomGenerator = new Random(System.currentTimeMillis()); CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); - String[] coList = new String[numberOfObjects]; + String[] coList = new String[numberOfObjects]; + + // + // First create a CollectionObject + // + CollectionobjectsCommon co = new CollectionobjectsCommon(); + fillCollectionObject(co, Long.toString(System.currentTimeMillis())); + + // Next, create a part object + MultipartOutput multipart = new MultipartOutput(); + OutputPart commonPart = multipart.addPart(co, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", collectionObjectClient.getCommonPartName()); int createdObjects = 0; try { Date startTime = new Date(); for (int i = 0; i < numberOfObjects; i++, createdObjects++) { - coList[i] = createCollectionObject(collectionObjectClient, i + 1); + coList[i] = createCollectionObject(collectionObjectClient, multipart); if (logger.isDebugEnabled() == true) { - logger.debug("Created CollectionObject #: " + i); + // + // Print out a status every 10 operations + if (i % 10 == 0) + logger.debug("Created CollectionObject #: " + i); } } Date stopTime = new Date(); @@ -237,7 +242,78 @@ public class PerformanceTest extends CollectionSpacePerformanceTest { return coList; } + // + // + // + + /** + * Delete collection object. + * + * @param collectionObjectClient the collection object client + * @param resourceId the resource id + */ + private void readCollectionObject(CollectionObjectClient collectionObjectClient, + String resourceId) { + ClientResponse res = collectionObjectClient.delete(resourceId); + res.releaseConnection(); + } + + /** + * Delete collection objects. + * + * @param arrayOfObjects the array of objects + */ + public void readCollectionObjects(String[] arrayOfObjects) { + CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); + + Date startTime = new Date(); + for (int i = 0; i < arrayOfObjects.length; i++) { + deleteCollectionObject(collectionObjectClient, arrayOfObjects[i]); + } + Date stopTime = new Date(); + + if (logger.isDebugEnabled()) { + System.out.println("Read " + arrayOfObjects.length + " CollectionObjects" + + " in " + (stopTime.getTime() - startTime.getTime())/1000.0 + " seconds."); + } + } + + /** + * Delete collection objects. + * FIXME: Deletes a page at a time until there are no more CollectionObjects. + */ + public void readCollectionObjects() { + CollectionObjectClient collectionObjectClient = new CollectionObjectClient(); + ClientResponse response; + + List coListItems = null; + do { + response = collectionObjectClient.readList(new Long(MAX_RECORDS), + new Long(0)); + try { + CollectionobjectsCommonList commonListElement = + (CollectionobjectsCommonList)response.getEntity(CollectionobjectsCommonList.class); + coListItems = commonListElement.getCollectionObjectListItem(); + } finally { + response.releaseConnection(); + } + + Date startTime = new Date(); + for (CollectionObjectListItem i:coListItems) { + readCollectionObject(collectionObjectClient, i.getCsid()); + } + Date stopTime = new Date(); + + if (logger.isDebugEnabled()) { + System.out.println("Read " + coListItems.size() + " CollectionObjects" + + " in " + (stopTime.getTime() - startTime.getTime())/1000.0 + " seconds."); + } + } while (coListItems.size() > 0); + } + // + // + // /** * Delete collection object. * @@ -280,8 +356,8 @@ public class PerformanceTest extends CollectionSpacePerformanceTest { List coListItems = null; do { - response = collectionObjectClient.readList(Integer.toString(MAX_RECORDS), - Integer.toString(0)); + response = collectionObjectClient.readList(new Long(MAX_RECORDS), + new Long(0)); try { CollectionobjectsCommonList commonListElement = (CollectionobjectsCommonList)response.getEntity(CollectionobjectsCommonList.class); diff --git a/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/PermissionServiceTest.java b/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/PermissionServiceTest.java index 880735e12..0bd3d0147 100644 --- a/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/PermissionServiceTest.java +++ b/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/PermissionServiceTest.java @@ -411,9 +411,10 @@ public class PermissionServiceTest extends AbstractServiceTestImpl { Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - int EXPECTED_ITEMS = 5; //seeded permissions + int EXPECTED_ITEMS = 3; //seeded permissions + int actual = list.getPermissions().size(); if (logger.isDebugEnabled()) { - logger.debug(testName + ": received = " + list.getPermissions().size() + logger.debug(testName + ": received = " + actual + " expected=" + EXPECTED_ITEMS); } Assert.assertEquals(EXPECTED_ITEMS, list.getPermissions().size()); diff --git a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java index e73f9b913..d4341270d 100644 --- a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java +++ b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java @@ -48,6 +48,7 @@ import org.collectionspace.services.authorization.SubjectType; import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; import org.collectionspace.services.common.service.ServiceBindingType; import org.collectionspace.services.common.tenant.TenantBindingType; +import org.collectionspace.services.common.security.SecurityUtils; /** * AuthorizationGen generates authorizations (permissions and roles) @@ -111,21 +112,26 @@ public class AuthorizationGen { for (ServiceBindingType sbinding : tbinding.getServiceBindings()) { //add permissions for the main path + String resourceName = sbinding.getName().toLowerCase().trim(); + if (SecurityUtils.isEntityProxy() == true) { + resourceName = SecurityUtils.getResourceEntity(resourceName); + } Permission perm = buildAdminPermission(tbinding.getId(), - sbinding.getName().toLowerCase()); + resourceName); apcList.add(perm); //add permissions for alternate paths - List uriPaths = sbinding.getUriPath(); - for (String uriPath : uriPaths) { - perm = buildAdminPermission(tbinding.getId(), - uriPath.toLowerCase()); - apcList.add(perm); + if (SecurityUtils.isEntityProxy() == false) { + List uriPaths = sbinding.getUriPath(); + for (String uriPath : uriPaths) { + perm = buildAdminPermission(tbinding.getId(), + uriPath.toLowerCase()); + apcList.add(perm); + } } - } + return apcList; - } private Permission buildAdminPermission(String tenantId, String resourceName) { @@ -134,7 +140,7 @@ public class AuthorizationGen { perm.setCsid(id); perm.setDescription("generated admin permission"); perm.setCreatedAtItem(new Date()); - perm.setResourceName(resourceName.toLowerCase()); + perm.setResourceName(resourceName.toLowerCase().trim()); perm.setEffect(EffectType.PERMIT); perm.setTenantId(tenantId); ArrayList pas = new ArrayList(); @@ -168,20 +174,24 @@ public class AuthorizationGen { ArrayList apcList = new ArrayList(); TenantBindingType tbinding = tenantBindings.get(tenantId); for (ServiceBindingType sbinding : tbinding.getServiceBindings()) { - //add permissions for the main path + String resourceName = sbinding.getName().toLowerCase().trim(); + if (SecurityUtils.isEntityProxy() == true) { + resourceName = SecurityUtils.getResourceEntity(resourceName); + } Permission perm = buildReaderPermission(tbinding.getId(), - sbinding.getName().toLowerCase()); + resourceName); apcList.add(perm); //add permissions for alternate paths - List uriPaths = sbinding.getUriPath(); - for (String uriPath : uriPaths) { - perm = buildReaderPermission(tbinding.getId(), - uriPath.toLowerCase()); - apcList.add(perm); + if (SecurityUtils.isEntityProxy() == false) { + List uriPaths = sbinding.getUriPath(); + for (String uriPath : uriPaths) { + perm = buildReaderPermission(tbinding.getId(), + uriPath.toLowerCase()); + apcList.add(perm); + } } - } return apcList; @@ -193,7 +203,7 @@ public class AuthorizationGen { perm.setCsid(id); perm.setCreatedAtItem(new Date()); perm.setDescription("generated readonly permission"); - perm.setResourceName(resourceName.toLowerCase()); + perm.setResourceName(resourceName.toLowerCase().trim()); perm.setEffect(EffectType.PERMIT); perm.setTenantId(tenantId); ArrayList pas = new ArrayList(); diff --git a/services/authorization/jaxb/src/main/resources/permissions.xsd b/services/authorization/jaxb/src/main/resources/permissions.xsd index d0ed3f161..0107371e4 100644 --- a/services/authorization/jaxb/src/main/resources/permissions.xsd +++ b/services/authorization/jaxb/src/main/resources/permissions.xsd @@ -52,6 +52,8 @@ no need to give slash at the beginning or end - attributeName could be an attribute of the service schema e.g. otherNumber from collectionobjects_common + - actionGroup is label that can be used by a client to "group" sets of actions for operations + like searching for permissions by a specific actionGroup label. - action describes the actions that could be taken on given resource (and attribute) - effect describes the effect of the access control for the action performed on the given resource (and attribute) @@ -91,6 +93,15 @@ + + + + + + + + + diff --git a/services/authorization/pstore/src/main/resources/db/mysql/authorization.sql b/services/authorization/pstore/src/main/resources/db/mysql/authorization.sql index 24c77efb0..78d80a785 100644 --- a/services/authorization/pstore/src/main/resources/db/mysql/authorization.sql +++ b/services/authorization/pstore/src/main/resources/db/mysql/authorization.sql @@ -5,7 +5,7 @@ drop table if exists permissions_actions; drop table if exists permissions_roles; drop table if exists roles; create table accounts_roles (HJID bigint not null auto_increment, account_id varchar(128) not null, created_at datetime not null, role_id varchar(128) not null, role_name varchar(255), screen_name varchar(255), user_id varchar(128) not null, primary key (HJID), unique (account_id, role_id)); -create table permissions (csid varchar(128) not null, attribute_name varchar(128), created_at datetime not null, description varchar(255), effect varchar(32) not null, resource_name varchar(128) not null, tenant_id varchar(128) not null, updated_at datetime, primary key (csid)); +create table permissions (csid varchar(128) not null, action_group varchar(128), attribute_name varchar(128), created_at datetime not null, description varchar(255), effect varchar(32) not null, resource_name varchar(128) not null, tenant_id varchar(128) not null, updated_at datetime, primary key (csid)); create table permissions_actions (HJID bigint not null auto_increment, name varchar(128) not null, ACTIONS_PERMISSION_CSID varchar(128), primary key (HJID)); create table permissions_roles (HJID bigint not null auto_increment, created_at datetime not null, permission_id varchar(128) not null, permission_resource varchar(255), role_id varchar(128) not null, role_name varchar(255), primary key (HJID), unique (permission_id, role_id)); create table roles (csid varchar(128) not null, created_at datetime not null, description varchar(255), rolegroup varchar(255), rolename varchar(200) not null, tenant_id varchar(128) not null, updated_at datetime, primary key (csid), unique (rolename, tenant_id)); diff --git a/services/authorization/service/src/main/java/org/collectionspace/services/authorization/AuthZ.java b/services/authorization/service/src/main/java/org/collectionspace/services/authorization/AuthZ.java index a4a416bff..15198681e 100644 --- a/services/authorization/service/src/main/java/org/collectionspace/services/authorization/AuthZ.java +++ b/services/authorization/service/src/main/java/org/collectionspace/services/authorization/AuthZ.java @@ -55,7 +55,7 @@ public class AuthZ { public final static AuthZ get() { return self; } - + private void setupProvider() { String beanConfig = "applicationContext-authorization.xml"; //system property is only set in test environment diff --git a/services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java b/services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java index 3ea1e7e21..b58dc5b41 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java +++ b/services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java @@ -307,8 +307,8 @@ public abstract class AbstractServiceClientImpl implements * .lang.String, java.lang.String) */ @Override - public ClientResponse readList(String pageSize, - String pageNumber) { + public ClientResponse readList(Long pageSize, + Long pageNumber) { return getProxy().readList(pageSize, pageNumber); } @@ -320,8 +320,8 @@ public abstract class AbstractServiceClientImpl implements * .lang.String, java.lang.String) */ @Override - public ClientResponse readList(String sortBy, String pageSize, - String pageNumber) { + public ClientResponse readList(String sortBy, Long pageSize, + Long pageNumber) { return getProxy().readList(sortBy, pageSize, pageNumber); } diff --git a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java index 022380679..8da8cb8e9 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java +++ b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java @@ -149,8 +149,8 @@ public interface CollectionSpaceClient { * @return the client response */ public ClientResponse readList( - String pageSize, - String pageNumber); + Long pageSize, + Long pageNumber); /** * Read list. @@ -162,8 +162,8 @@ public interface CollectionSpaceClient { */ public ClientResponse readList( String sortBy, - String pageSize, - String pageNumber); + Long pageSize, + Long pageNumber); /** * Delete. diff --git a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java index f95894ab7..b9a02d3f2 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java +++ b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java @@ -49,11 +49,12 @@ public interface CollectionSpaceProxy { @GET @Produces({"application/xml"}) ClientResponse readList( - @QueryParam(IClientQueryParams.PAGE_SIZE_PARAM) String pageSize, - @QueryParam(IClientQueryParams.START_PAGE_PARAM) String pageNumber); + @QueryParam(IClientQueryParams.PAGE_SIZE_PARAM) Long pageSize, + @QueryParam(IClientQueryParams.START_PAGE_PARAM) Long pageNumber); /** * Read list. + * @param sortBy * * @param pageSize the page size * @param pageNumber the page number @@ -63,6 +64,6 @@ public interface CollectionSpaceProxy { @Produces({"application/xml"}) ClientResponse readList( @QueryParam(IClientQueryParams.SORT_BY_PARAM) String sortBy, - @QueryParam(IClientQueryParams.PAGE_SIZE_PARAM) String pageSize, - @QueryParam(IClientQueryParams.START_PAGE_PARAM) String pageNumber); + @QueryParam(IClientQueryParams.PAGE_SIZE_PARAM) Long pageSize, + @QueryParam(IClientQueryParams.START_PAGE_PARAM) Long pageNumber); } diff --git a/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java b/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java index 1ffe52542..318841c95 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java +++ b/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java @@ -408,7 +408,7 @@ public abstract class AbstractServiceTestImpl extends BaseServiceTest implements CollectionSpaceClient client, String sortBy, long pageSize, long pageNumber) throws Exception { ClientResponse response = - client.readList(sortBy, Long.toString(pageSize), Long.toString(pageNumber)); + client.readList(sortBy, pageSize, pageNumber); AbstractCommonList result = null; try { int statusCode = response.getStatus(); diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java index 021879c4d..ed39f501a 100644 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java @@ -44,6 +44,7 @@ import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.MultivaluedMap; +import org.collectionspace.services.common.imaging.nuxeo.NuxeoImageUtils; import org.collectionspace.services.common.AbstractMultiPartCollectionSpaceResourceImpl; import org.collectionspace.services.common.authorityref.AuthorityRefList; import org.collectionspace.services.common.context.ServiceContextFactory; @@ -489,6 +490,25 @@ public class CollectionObjectResource return result; } + + @GET + @Path("/picture") + @Produces("application/xml") + public Response createPictureDocument() { + Response result = null; + + if (logger.isDebugEnabled()) { + logger.debug("------------------------------------------------------------------------------"); + logger.debug("Prototype to create a Picture document in Nuxeo"); + logger.debug("------------------------------------------------------------------------------"); + logger.debug(""); + } + + NuxeoImageUtils.createPicture(); + result = Response.status(HttpResponseCodes.SC_OK).build(); + + return result; + } /** * This method is deprecated. Use kwSearchCollectionObjects() method instead. diff --git a/services/common/pom.xml b/services/common/pom.xml index cdf19397c..fed04ab54 100644 --- a/services/common/pom.xml +++ b/services/common/pom.xml @@ -159,6 +159,11 @@ provided + + org.nuxeo.ecm.platform + nuxeo-platform-imaging-api + ${nuxeo.version.5.2} + org.nuxeo.common nuxeo-common diff --git a/services/common/src/main/java/org/collectionspace/services/common/document/DocumentUtils.java b/services/common/src/main/java/org/collectionspace/services/common/document/DocumentUtils.java index b15b38030..cff812ba5 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/document/DocumentUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/document/DocumentUtils.java @@ -132,7 +132,6 @@ public class DocumentUtils { String s = new String(buff); logger.debug(s); - System.out.println(s); //FIXME: REM - Remove this when we figure out why the logger.debug() call is not working. // // Essentially, reset the stream and return it in its original state // @@ -142,19 +141,53 @@ public class DocumentUtils { return result; } + /** + * Gets the xML schema. + * + * @param partMeta the part meta + * @return the xML schema + * @throws Exception the exception + */ + private static File getXMLSchema(ObjectPartType partMeta) + throws Exception { + final String FILE_SEPARATOR = System.getProperty("file.separator"); + final String XML_SCHEMA_EXTENSION = ".xsd"; + final String SCHEMAS_DIR = "schemas"; + + File schemaFile = null; + + // + // Look for an XML Schema (.xsd) file for the incoming part payload + // + String serverRoot = ServiceMain.getInstance().getServerRootDir(); + String schemasDir = serverRoot + FILE_SEPARATOR + + SCHEMAS_DIR + FILE_SEPARATOR; + // + // Send a warning to the log file if the XML Schema file is missing + // + String schemaName = schemasDir + partMeta.getLabel() + XML_SCHEMA_EXTENSION; + try { + schemaFile = new File(schemaName); + } catch (Exception e) { + if (logger.isWarnEnabled() == true) { + logger.warn("Missing schema file for incoming payload: " + schemaName); + } + } + + return schemaFile; + } + /** * parseProperties given payload to create XML document. this * method also closes given stream after parsing. * @param payload stream * @param partMeta + * @param validate - whether or not to validate the payload with an XML Schema * @return parsed Document * @throws Exception */ - public static Document parseDocument(InputStream payload, ObjectPartType partMeta) + public static Document parseDocument(InputStream payload, ObjectPartType partMeta, Boolean validate) throws Exception { - final String FILE_SEPARATOR = System.getProperty("file.separator"); - final String XML_SCHEMA_EXTENSION = ".xsd"; - final String SCHEMAS_DIR = "schemas"; final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; final String JAXP_SCHEMA_LANGUAGE = @@ -169,23 +202,10 @@ public class DocumentUtils { payload = logByteArrayInputStream((ByteArrayInputStream)payload); } } - // - // Look for an XML Schema (.xsd) file for the incoming part payload - // - String serverRoot = ServiceMain.getInstance().getServerRootDir(); - String schemasDir = serverRoot + FILE_SEPARATOR + - SCHEMAS_DIR + FILE_SEPARATOR; - // - // Send a warning to the log file if the XML Schema file is missing - // - String schemaName = schemasDir + partMeta.getLabel() + XML_SCHEMA_EXTENSION; + File schemaFile = null; - try { - schemaFile = new File(schemaName); - } catch (Exception e) { - if (logger.isWarnEnabled() == true) { - logger.warn("Missing schema file for incoming payload: " + schemaName); - } + if (validate == true) { + schemaFile = getXMLSchema(partMeta); } // @@ -202,13 +222,13 @@ public class DocumentUtils { factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); // - // Enable XML validation + // Enable XML validation if we found an XML Schema for the payload // - factory.setNamespaceAware(true); - factory.setValidating(true); try { - factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); if (schemaFile != null) { + factory.setValidating(true); + factory.setNamespaceAware(true); + factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); factory.setAttribute(JAXP_SCHEMA_SOURCE, schemaFile); } } catch (IllegalArgumentException e) { @@ -452,10 +472,10 @@ public class DocumentUtils { root.setAttribute("xsi:schemaLocation", xc.getSchemaLocation()); root.setAttribute("xmlns:" + ns, xc.getNamespaceURI()); document.appendChild(root); - + SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class); Schema schema = schemaManager.getSchema(partMeta.getLabel()); - + buildDocument(document, root, objectProps, schema); return document; @@ -489,7 +509,7 @@ public class DocumentUtils { private static void buildProperty(Document document, Element parent, Field field, Object value) throws IOException { Type type = field.getType(); - //no need to qualify each element name as namespace is already added + //no need to qualify each element name as namespace is already added String propName = field.getName().getLocalName(); Element element = document.createElement(propName); parent.appendChild(element); @@ -501,9 +521,9 @@ public class DocumentUtils { if (ctype.getName().equals(TypeConstants.CONTENT)) { throw new RuntimeException( "Unexpected schema type: BLOB for field: "+propName); - } else { + } else { buildComplex(document, element, ctype, (Map) value); - } + } } else if (type.isListType()) { if (value instanceof List) { buildList(document, element, (ListType) type, (List) value); @@ -514,10 +534,10 @@ public class DocumentUtils { throw new IllegalArgumentException( "A value of list type is neither list neither array: " + value); - } - } + } + } } - + private static void buildComplex(Document document, Element element, ComplexType ctype, Map map) throws IOException { Iterator it = map.entrySet().iterator(); diff --git a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java index cd54396ac..5010db2ba 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java +++ b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java @@ -28,6 +28,8 @@ package org.collectionspace.services.common.security; import java.util.HashMap; +import java.util.List; + import org.jboss.resteasy.core.ResourceMethod; import org.jboss.resteasy.core.ServerResponse; import org.jboss.resteasy.spi.interception.PreProcessInterceptor; @@ -38,6 +40,7 @@ import org.jboss.resteasy.spi.HttpRequest; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.PathSegment; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Provider; @@ -47,6 +50,7 @@ import org.collectionspace.services.authorization.CSpaceResource; import org.collectionspace.services.authorization.URIResourceImpl; import org.collectionspace.services.common.document.JaxbUtils; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; +import org.collectionspace.services.common.security.SecurityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,97 +63,118 @@ import org.slf4j.LoggerFactory; @Provider public class SecurityInterceptor implements PreProcessInterceptor { - private static final Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class); - - @Override - public ServerResponse preProcess(HttpRequest request, ResourceMethod method) - throws Failure, WebApplicationException { - String httpMethod = request.getHttpMethod(); - String uriPath = request.getUri().getPath(); - if (logger.isDebugEnabled()) { - logger.debug("received " + httpMethod + " on " + uriPath); - } - String resName = getResourceName(request.getUri()); - checkActive(); - AuthZ authZ = AuthZ.get(); - CSpaceResource res = new URIResourceImpl(resName, httpMethod); - if (!authZ.isAccessAllowed(res)) { - logger.error("Access to " + res.getId() + " is NOT allowed to " - + " user=" + AuthN.get().getUserId()); - Response response = Response.status( - Response.Status.FORBIDDEN).entity(uriPath + " " + httpMethod).type("text/plain").build(); - throw new WebApplicationException(response); - } - if (logger.isDebugEnabled()) { - logger.debug("Access to " + res.getId() + " is allowed to " - + " user=" + AuthN.get().getUserId() + - " for tenant id=" + AuthN.get().getCurrentTenantName()); - } - return null; - } - - /** - * checkActive check if account is active - * @throws WebApplicationException - */ - private void checkActive() throws WebApplicationException { - String userId = AuthN.get().getUserId(); - String tenantId = AuthN.get().getCurrentTenantId(); - try { - //can't use JAXB here as this runs from the common jar which cannot - //depend upon the account service - String whereClause = "where userId = :userId"; - HashMap params = new HashMap(); - params.put("userId", userId); - - Object account = JpaStorageUtils.getEntity( - "org.collectionspace.services.account.AccountsCommon", whereClause, params); - if (account == null) { - String msg = "User's account not found, userId=" + userId; - Response response = Response.status( - Response.Status.FORBIDDEN).entity(msg).type("text/plain").build(); - throw new WebApplicationException(response); - } - Object status = JaxbUtils.getValue(account, "getStatus"); - if (status != null) { - String value = (String) JaxbUtils.getValue(status, "value"); - if ("INACTIVE".equalsIgnoreCase(value)) { - String msg = "User's account is inactive, userId=" + userId; - Response response = Response.status( - Response.Status.FORBIDDEN).entity(msg).type("text/plain").build(); - throw new WebApplicationException(response); - } - } - - } catch (Exception e) { - String msg = "User's account is in invalid state, userId=" + userId; - Response response = Response.status( - Response.Status.FORBIDDEN).entity(msg).type("text/plain").build(); - throw new WebApplicationException(response); - } - } - - private String getResourceName(UriInfo uriInfo) { - String uriPath = uriInfo.getPath(); - MultivaluedMap pathParams = uriInfo.getPathParameters(); - for (String pathParamName : pathParams.keySet()) { - //assumption : path params for csid for any entity has substring csid in name - String pathParamValue = pathParams.get(pathParamName).get(0); - if ((pathParamName.toLowerCase().indexOf("csid") > -1)) { - //replace csids with wildcard - uriPath = uriPath.replace(pathParamValue, "*"); - } - if ((pathParamName.toLowerCase().indexOf("predicate") > -1)) { - //replace csids with wildcard - uriPath = uriPath.replace(pathParamValue, "*"); - } - if (pathParamName.toLowerCase().indexOf("specifier") > -1) { - //replace name and specifiers with wildcard - uriPath = uriPath.replace("urn:cspace:name(" + pathParamValue - + ")", "*"); - } - } - uriPath = uriPath.replace("//", "/"); - return uriPath; - } + /** The Constant logger. */ + private static final Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class); + + /* (non-Javadoc) + * @see org.jboss.resteasy.spi.interception.PreProcessInterceptor#preProcess(org.jboss.resteasy.spi.HttpRequest, org.jboss.resteasy.core.ResourceMethod) + */ + @Override + public ServerResponse preProcess(HttpRequest request, ResourceMethod method) + throws Failure, WebApplicationException { + String httpMethod = request.getHttpMethod(); + String uriPath = request.getUri().getPath(); + if (logger.isDebugEnabled()) { + logger.debug("received " + httpMethod + " on " + uriPath); + } + String resName = getResourceName(request.getUri()); + String resEntity = SecurityUtils.getResourceEntity(resName); + + // + // If the resource entity is acting as a proxy then all sub-resource will map to the resource itself. + // This essentially means that the sub-resource inherit all the authz permissions of the entity. + // + if (SecurityUtils.isEntityProxy() == true) { + resName = resEntity; + } + + checkActive(); + AuthZ authZ = AuthZ.get(); + CSpaceResource res = new URIResourceImpl(resName, httpMethod); + if (!authZ.isAccessAllowed(res)) { + logger.error("Access to " + res.getId() + " is NOT allowed to " + + " user=" + AuthN.get().getUserId()); + Response response = Response.status( + Response.Status.FORBIDDEN).entity(uriPath + " " + httpMethod).type("text/plain").build(); + throw new WebApplicationException(response); + } + if (logger.isDebugEnabled()) { + logger.debug("Access to " + res.getId() + " is allowed to " + + " user=" + AuthN.get().getUserId() + + " for tenant id=" + AuthN.get().getCurrentTenantName()); + } + return null; + } + + /** + * checkActive check if account is active + * @throws WebApplicationException + */ + private void checkActive() throws WebApplicationException { + String userId = AuthN.get().getUserId(); + String tenantId = AuthN.get().getCurrentTenantId(); + try { + //can't use JAXB here as this runs from the common jar which cannot + //depend upon the account service + String whereClause = "where userId = :userId"; + HashMap params = new HashMap(); + params.put("userId", userId); + + Object account = JpaStorageUtils.getEntity( + "org.collectionspace.services.account.AccountsCommon", whereClause, params); + if (account == null) { + String msg = "User's account not found, userId=" + userId; + Response response = Response.status( + Response.Status.FORBIDDEN).entity(msg).type("text/plain").build(); + throw new WebApplicationException(response); + } + Object status = JaxbUtils.getValue(account, "getStatus"); + if (status != null) { + String value = (String) JaxbUtils.getValue(status, "value"); + if ("INACTIVE".equalsIgnoreCase(value)) { + String msg = "User's account is inactive, userId=" + userId; + Response response = Response.status( + Response.Status.FORBIDDEN).entity(msg).type("text/plain").build(); + throw new WebApplicationException(response); + } + } + + } catch (Exception e) { + String msg = "User's account is in invalid state, userId=" + userId; + Response response = Response.status( + Response.Status.FORBIDDEN).entity(msg).type("text/plain").build(); + throw new WebApplicationException(response); + } + } + + /** + * Gets the resource name. + * + * @param uriInfo the uri info + * @return the resource name + */ + private String getResourceName(UriInfo uriInfo) { + String uriPath = uriInfo.getPath(); + + MultivaluedMap pathParams = uriInfo.getPathParameters(); + for (String pathParamName : pathParams.keySet()) { + //assumption : path params for csid for any entity has substring csid in name + String pathParamValue = pathParams.get(pathParamName).get(0); + if ((pathParamName.toLowerCase().indexOf("csid") > -1)) { + //replace csids with wildcard + uriPath = uriPath.replace(pathParamValue, "*"); + } + if ((pathParamName.toLowerCase().indexOf("predicate") > -1)) { + //replace csids with wildcard + uriPath = uriPath.replace(pathParamValue, "*"); + } + if (pathParamName.toLowerCase().indexOf("specifier") > -1) { + //replace name and specifiers with wildcard + uriPath = uriPath.replace("urn:cspace:name(" + pathParamValue + + ")", "*"); + } + } + uriPath = uriPath.replace("//", "/"); + return uriPath; + } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityUtils.java b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityUtils.java index de57be1ad..e1c54840f 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityUtils.java @@ -22,6 +22,14 @@ */ package org.collectionspace.services.common.security; +import java.util.List; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.StringTokenizer; + +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.UriInfo; + import org.collectionspace.authentication.AuthN; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +41,7 @@ import org.slf4j.LoggerFactory; public class SecurityUtils { private static final Logger logger = LoggerFactory.getLogger(SecurityUtils.class); + public static final String URI_PATH_SEPARATOR = "/"; /** * createPasswordHash creates password has using configured digest algorithm @@ -68,6 +77,66 @@ public class SecurityUtils { } } + /** + * Gets the resource name. + * + * @param uriInfo the uri info + * @return the resource name + */ + public static String getResourceEntity(UriInfo uriInfo) { + String result = null; + + result = getResourceEntity(uriInfo.getPath()); +// List pathSegmentList = uriInfo.getPathSegments(); +// if (pathSegmentList.isEmpty() == false) { +// result = pathSegmentList.get(0).getPath(); +// } + + return result; + } + + /** + * Gets the resource entity by returning the first segment of the resource path + * + * @param relativePath the relative path + * @return the resource entity + * @throws URISyntaxException the uRI syntax exception + */ + public static String getResourceEntity(String relativePath) + { + String result = ""; + + StringTokenizer strTok = new StringTokenizer(relativePath, URI_PATH_SEPARATOR); + String pathSegment = null; + while (strTok.hasMoreTokens() == true) { + pathSegment = strTok.nextToken(); + if (pathSegment.equals("*") == true) { + // + // leave the loop if we hit a wildcard character + // + break; + } + if (result.length() > 0) { + result = result.concat(URI_PATH_SEPARATOR); + } + result = result.concat(pathSegment); + } + + return result; + } + + /** + * Checks if is entity is action as a proxy for all sub-resources. + * + * @return true, if is entity proxy is acting as a proxy for all sub-resources + */ + public static final boolean isEntityProxy() { + // + // should be getting this information from the cspace config settings (tenent bindings file). + return true; + } + + /** * isCSpaceAdmin check if authenticated user is a CSpace administrator * @param tenantId diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java index 8785252d8..51b8fc4e6 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java @@ -227,7 +227,8 @@ public abstract class RemoteDocumentModelHandlerImpl //check if this is an xml part if(part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)){ if(payload != null){ - Document document = DocumentUtils.parseDocument(payload, partMeta); + Document document = DocumentUtils.parseDocument(payload, partMeta, + false /*don't validate*/); //TODO: callback to handler if registered to validate the //document Map objectProps = DocumentUtils.parseProperties(document.getFirstChild()); diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteSubItemDocumentModelHandlerImpl.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteSubItemDocumentModelHandlerImpl.java index 9ebc7cd57..2b9f88051 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteSubItemDocumentModelHandlerImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteSubItemDocumentModelHandlerImpl.java @@ -75,7 +75,8 @@ public abstract class RemoteSubItemDocumentModelHandlerImpl extends // and then check that here, so skip other parts. if(part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)){ if(payload != null){ - Document document = DocumentUtils.parseDocument(payload, partMeta); + Document document = DocumentUtils.parseDocument(payload, partMeta, + false /*don't validate*/); //TODO: callback to handler if registered to validate the //document Map objectProps = DocumentUtils.parseProperties(document.getFirstChild()); diff --git a/services/location/jaxb/.classpath b/services/location/jaxb/.classpath index 425cd1620..98a63fe9a 100644 --- a/services/location/jaxb/.classpath +++ b/services/location/jaxb/.classpath @@ -1,6 +1,7 @@ + diff --git a/services/relation/client/pom.xml b/services/relation/client/pom.xml index 34d301745..cce3d0b90 100644 --- a/services/relation/client/pom.xml +++ b/services/relation/client/pom.xml @@ -36,6 +36,12 @@ org.collectionspace.services.client ${project.version} + + org.collectionspace.services + org.collectionspace.services.common + true + ${project.version} + org.testng diff --git a/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java b/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java index 836bf9382..4dd699bf7 100644 --- a/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java +++ b/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java @@ -102,18 +102,33 @@ public class RelationClient extends AbstractServiceClientImpl { } /** - * Read list_ spo. + * Read list. * * @param subjectCsid the subject csid * @param predicate the predicate * @param objectCsid the object csid * @return the client response */ - public ClientResponse readList_SPO(String subjectCsid, - String predicate, String objectCsid) { - return relationProxy.readList_SPO(subjectCsid, predicate, objectCsid); + public ClientResponse readList(String subjectCsid, + String predicate, + String objectCsid) { + return relationProxy.readList(subjectCsid, predicate, objectCsid); } +// /** +// * Read list_ spo. +// * +// * @param subjectCsid the subject csid +// * @param predicate the predicate +// * @param objectCsid the object csid +// * @return the client response +// */ +// @Deprecated +// public ClientResponse readList_SPO(String subjectCsid, +// String predicate, String objectCsid) { +// return relationProxy.readList_SP0(subjectCsid, predicate, objectCsid); +// } + /** * Read. * diff --git a/services/relation/client/src/main/java/org/collectionspace/services/client/RelationProxy.java b/services/relation/client/src/main/java/org/collectionspace/services/client/RelationProxy.java index 352f4f3b8..19eaaf131 100644 --- a/services/relation/client/src/main/java/org/collectionspace/services/client/RelationProxy.java +++ b/services/relation/client/src/main/java/org/collectionspace/services/client/RelationProxy.java @@ -11,9 +11,12 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Response; import org.collectionspace.services.relation.RelationsCommonList; +import org.collectionspace.services.common.relation.IRelationsManager; + import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; +import javax.ws.rs.QueryParam; /** * @version $Revision:$ @@ -26,13 +29,22 @@ public interface RelationProxy extends CollectionSpaceProxy { @GET @Produces({"application/xml"}) ClientResponse readList(); - + @GET @Produces({"application/xml"}) - @Path("subject/{subjectCsid}/type/{predicate}/object/{objectCsid}") - ClientResponse readList_SPO(@PathParam("subjectCsid") String subjectCsid, - @PathParam("predicate") String predicate, - @PathParam("objectCsid") String objectCsid); + ClientResponse readList( + @QueryParam(IRelationsManager.SUBJECT_QP) String subjectCsid, + @QueryParam(IRelationsManager.PREDICATE_QP) String predicate, + @QueryParam(IRelationsManager.OBJECT_QP) String objectCsid); + +// @GET +// @Produces({"application/xml"}) +// @Path("subject/{subjectCsid}/type/{predicate}/object/{objectCsid}") +// @Deprecated +// ClientResponse readList_SPO( +// @PathParam("subjectCsid") String subjectCsid, +// @PathParam("predicate") String predicate, +// @PathParam("objectCsid") String objectCsid); //(C)reate @POST diff --git a/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java b/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java index 175d52407..a87835b17 100644 --- a/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java +++ b/services/relation/service/src/main/java/org/collectionspace/services/relation/NewRelationResource.java @@ -34,6 +34,7 @@ import javax.ws.rs.DELETE; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; @@ -42,6 +43,7 @@ import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import org.collectionspace.services.common.query.IQueryManager; +import org.collectionspace.services.common.relation.IRelationsManager; import org.collectionspace.services.common.relation.nuxeo.RelationsUtils; import org.collectionspace.services.common.AbstractMultiPartCollectionSpaceResourceImpl; import org.collectionspace.services.common.context.ServiceContext; @@ -200,14 +202,20 @@ public class NewRelationResource extends * Gets the relation list. * * @param ui the ui + * @param subjectCsid + * @param predicate + * @param objectCsid * * @return the relation list */ @GET @Produces("application/xml") - public RelationsCommonList getRelationList(@Context UriInfo ui) { + public RelationsCommonList getRelationList(@Context UriInfo ui, + @QueryParam(IRelationsManager.SUBJECT_QP) String subjectCsid, + @QueryParam(IRelationsManager.PREDICATE_QP) String predicate, + @QueryParam(IRelationsManager.OBJECT_QP) String objectCsid) { MultivaluedMap queryParams = ui.getQueryParameters(); - return this.getRelationList(queryParams, null, null, null); + return this.getRelationList(queryParams, subjectCsid, predicate, objectCsid); } /** @@ -498,7 +506,7 @@ public class NewRelationResource extends RelationsCommonList relationList = new RelationsCommonList(); try { ServiceContext ctx = createServiceContext(queryParams); - DocumentHandler handler = createDocumentHandler(ctx); + DocumentHandler handler = createDocumentHandler(ctx); String relationClause = RelationsUtils.buildWhereClause(subjectCsid, predicate, objectCsid); handler.getDocumentFilter().appendWhereClause(relationClause, IQueryManager.SEARCH_QUALIFIER_AND); getRepositoryClient(ctx).getFiltered(ctx, handler); -- 2.47.3