From: Richard Millet Date: Sat, 19 Jan 2013 18:39:33 +0000 (-0800) Subject: CSPACE-5564: Added anonymous access Article service. X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=4033c279b68f3704e8ff31dd25885bd2c8650c63;p=tmp%2Fjakarta-migration.git CSPACE-5564: Added anonymous access Article service. --- diff --git a/pom.xml b/pom.xml index 98a49c1d9..24201912f 100644 --- a/pom.xml +++ b/pom.xml @@ -251,7 +251,7 @@ org.apache.maven.plugins maven-war-plugin - 2.0 + 2.1.1 WEB-INF/lib/*.jar diff --git a/services/JaxRsServiceProvider/pom.xml b/services/JaxRsServiceProvider/pom.xml index 79de463d1..c5bdd1591 100644 --- a/services/JaxRsServiceProvider/pom.xml +++ b/services/JaxRsServiceProvider/pom.xml @@ -31,6 +31,7 @@ log4j log4j 1.2.14 + provided @@ -198,6 +199,11 @@ org.collectionspace.services.dimension.service ${project.version} + + org.collectionspace.services + org.collectionspace.services.article.service + ${project.version} + org.collectionspace.services org.collectionspace.services.servicegroup.service @@ -345,7 +351,6 @@ servlet-api javax.servlet - 2.5 provided @@ -382,7 +387,6 @@ org.nuxeo.ecm.core nuxeo-core-api - ${nuxeo.core.version} org.nuxeo.ecm.core @@ -622,7 +626,6 @@ org.codehaus.mojo properties-maven-plugin - 1.0-alpha-2 initialize @@ -686,7 +689,6 @@ org.apache.maven.plugins maven-war-plugin - 2.1.1 diff --git a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java index f2e3aca03..33638e963 100644 --- a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java +++ b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java @@ -49,17 +49,14 @@ import org.collectionspace.services.contact.ContactResource; import org.collectionspace.services.vocabulary.VocabularyResource; import org.collectionspace.services.organization.OrgAuthorityResource; import org.collectionspace.services.person.PersonAuthorityResource; -import org.collectionspace.services.workflow.WorkflowResource; +import org.collectionspace.services.article.ArticleResource; //import org.collectionspace.services.query.QueryResource; import javax.servlet.ServletContext; import javax.ws.rs.core.Application; -import javax.ws.rs.core.Context; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; //import org.collectionspace.services.common.FileUtils; @@ -71,11 +68,6 @@ import org.collectionspace.services.common.ResourceMapHolder; import org.collectionspace.services.common.ResourceMapImpl; import org.collectionspace.services.common.relation.RelationResource; import org.collectionspace.services.common.security.SecurityInterceptor; -import org.jboss.resteasy.core.Dispatcher; -import org.jboss.resteasy.spi.ResteasyProviderFactory; -//import org.collectionspace.services.common.document.DocumentUtils; -//import org.collectionspace.services.common.imaging.nuxeo.NuxeoImageUtils; -//import org.collectionspace.services.common.profile.Profiler; /** * CollectionSpaceJaxRsApplication, the root application @@ -106,7 +98,6 @@ public class CollectionSpaceJaxRsApplication extends Application singletons.add(new ServiceGroupResource()); singletons.add(new ImportsResource()); - addResourceToMapAndSingletons(new VocabularyResource()); addResourceToMapAndSingletons(new PersonAuthorityResource()); addResourceToMapAndSingletons(new OrgAuthorityResource()); @@ -130,6 +121,7 @@ public class CollectionSpaceJaxRsApplication extends Application addResourceToMapAndSingletons(new BlobResource()); addResourceToMapAndSingletons(new MovementResource()); addResourceToMapAndSingletons(new ReportResource()); + addResourceToMapAndSingletons(new ArticleResource()); singletons.add(new IDResource()); @@ -146,7 +138,6 @@ public class CollectionSpaceJaxRsApplication extends Application resourceMap.put(resource.getServiceName(), resource); } - @Override public Set> getClasses() { return empty; diff --git a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/applicationContext-security.xml b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/applicationContext-security.xml index da685eea2..b00593d77 100644 --- a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/applicationContext-security.xml +++ b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/applicationContext-security.xml @@ -22,14 +22,18 @@ org.apache.catalina.core org.springframework.security --> - + + + + diff --git a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml index 2bd365af9..4515cb1f7 100644 --- a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml +++ b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml @@ -10,10 +10,12 @@ CollectionSpace Services + Sets the logging context for the Tiger web-app @@ -57,6 +59,7 @@ CSpaceFilter org.collectionspace.services.common.profile.CSpaceFilter + CSpaceFilter /* @@ -109,11 +112,21 @@ org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher - - + Resteasy /* + + + PublishedResourcesServlet + + org.collectionspace.services.common.servlet.PublishedResourcesServlet + + + + PublishedResourcesServlet + /published/* + diff --git a/services/article/3rdparty/build.xml b/services/article/3rdparty/build.xml new file mode 100644 index 000000000..35a6ae2a5 --- /dev/null +++ b/services/article/3rdparty/build.xml @@ -0,0 +1,127 @@ + + + + article service 3rdparty + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/article/3rdparty/nuxeo-platform-cs-article/build.xml b/services/article/3rdparty/nuxeo-platform-cs-article/build.xml new file mode 100644 index 000000000..7aa3ce53c --- /dev/null +++ b/services/article/3rdparty/nuxeo-platform-cs-article/build.xml @@ -0,0 +1,138 @@ + + + + article nuxeo document type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/article/3rdparty/nuxeo-platform-cs-article/pom.xml b/services/article/3rdparty/nuxeo-platform-cs-article/pom.xml new file mode 100644 index 000000000..65328eab6 --- /dev/null +++ b/services/article/3rdparty/nuxeo-platform-cs-article/pom.xml @@ -0,0 +1,56 @@ + + + + + org.collectionspace.services + org.collectionspace.services.article.3rdparty + 3.2.1-SNAPSHOT + + + 4.0.0 + org.collectionspace.services + org.collectionspace.services.article.3rdparty.nuxeo + services.article.3rdparty.nuxeo + jar + + Article Nuxeo Document Type + + + + article + Article + articles_common + cs_default + + + + + + src/main/resources + true + + + ../../../../3rdparty/nuxeo/nuxeo-doctype/src/main/resources + true + + + + + org.apache.maven.plugins + maven-jar-plugin + + + target/classes/META-INF/MANIFEST.MF + + ${eclipseVersion} + 2 + + + + + + + + diff --git a/services/article/3rdparty/nuxeo-platform-cs-article/src/main/resources/schemas/articles_common.xsd b/services/article/3rdparty/nuxeo-platform-cs-article/src/main/resources/schemas/articles_common.xsd new file mode 100644 index 000000000..479da4663 --- /dev/null +++ b/services/article/3rdparty/nuxeo-platform-cs-article/src/main/resources/schemas/articles_common.xsd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/services/article/3rdparty/pom.xml b/services/article/3rdparty/pom.xml new file mode 100644 index 000000000..d1e47f25d --- /dev/null +++ b/services/article/3rdparty/pom.xml @@ -0,0 +1,24 @@ + + + + org.collectionspace.services.article + org.collectionspace.services + 3.2.1-SNAPSHOT + + + 4.0.0 + org.collectionspace.services + org.collectionspace.services.article.3rdparty + services.article.3rdparty + pom + + + 3rd party build for article service + + + + nuxeo-platform-cs-article + + diff --git a/services/article/build.xml b/services/article/build.xml new file mode 100644 index 000000000..bfcb21183 --- /dev/null +++ b/services/article/build.xml @@ -0,0 +1,124 @@ + + + + article service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/article/client/pom.xml b/services/article/client/pom.xml new file mode 100644 index 000000000..056998ed3 --- /dev/null +++ b/services/article/client/pom.xml @@ -0,0 +1,94 @@ + + + + org.collectionspace.services + org.collectionspace.services.article + 3.2.1-SNAPSHOT + + + 4.0.0 + org.collectionspace.services + org.collectionspace.services.article.client + services.article.client + + + + + org.slf4j + slf4j-api + test + + + org.slf4j + slf4j-log4j12 + test + + + + org.collectionspace.services + org.collectionspace.services.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.common + true + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.article.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.person.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.authority.jaxb + ${project.version} + + + + org.testng + testng + + + org.jboss.resteasy + resteasy-jaxrs + + + + tjws + webserver + + + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + resteasy-multipart-provider + + + commons-httpclient + commons-httpclient + 3.1 + + + + + collectionspace-services-article-client + + diff --git a/services/article/client/src/main/java/org/collectionspace/services/client/ArticleClient.java b/services/article/client/src/main/java/org/collectionspace/services/client/ArticleClient.java new file mode 100644 index 000000000..403ab93c2 --- /dev/null +++ b/services/article/client/src/main/java/org/collectionspace/services/client/ArticleClient.java @@ -0,0 +1,52 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright (c) 2009 Regents of the University of California + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.client; + +/** + * ArticleClient.java + * + * $LastChangedRevision$ + * $LastChangedDate$ + * + */ +public class ArticleClient extends AbstractCommonListPoxServiceClientImpl { + + public static final String SERVICE_NAME = "articles"; + public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME; + public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT; + public static final String SERVICE_PATH_PROXY = SERVICE_PATH + "/"; + public static final String SERVICE_PAYLOAD_NAME = SERVICE_NAME; + + /* (non-Javadoc) + * @see org.collectionspace.services.client.AbstractServiceClientImpl#getServicePathComponent() + */ + @Override + public String getServicePathComponent() { + return SERVICE_PATH_COMPONENT; + } + + @Override + public String getServiceName() { + return SERVICE_NAME; + } + + @Override + public Class getProxyClass() { + return ArticleProxy.class; + } + +} diff --git a/services/article/client/src/main/java/org/collectionspace/services/client/ArticleProxy.java b/services/article/client/src/main/java/org/collectionspace/services/client/ArticleProxy.java new file mode 100644 index 000000000..d5f8dea80 --- /dev/null +++ b/services/article/client/src/main/java/org/collectionspace/services/client/ArticleProxy.java @@ -0,0 +1,34 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright (c) 2009 Regents of the University of California + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.client; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +/** + * ArticleProxy.java + * + * $LastChangedRevision$ + * $LastChangedDate$ + * + */ +@Path(ArticleClient.SERVICE_PATH_PROXY) +@Produces({"application/xml"}) +@Consumes({"application/xml"}) +public interface ArticleProxy extends CollectionSpaceCommonListPoxProxy { +} diff --git a/services/article/client/src/test/java/org/collectionspace/services/client/test/ArticleServiceTest.java b/services/article/client/src/test/java/org/collectionspace/services/client/test/ArticleServiceTest.java new file mode 100644 index 000000000..9a87e87a8 --- /dev/null +++ b/services/article/client/src/test/java/org/collectionspace/services/client/test/ArticleServiceTest.java @@ -0,0 +1,646 @@ +/** + * 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 Regents of the University of California + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.client.test; + +//import java.util.ArrayList; +import javax.ws.rs.core.Response; + +import org.collectionspace.services.client.AbstractCommonListUtils; +import org.collectionspace.services.client.CollectionSpaceClient; +import org.collectionspace.services.client.ArticleClient; +import org.collectionspace.services.client.PayloadInputPart; +import org.collectionspace.services.client.PayloadOutputPart; +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.common.api.GregorianCalendarDateTimeUtils; +import org.collectionspace.services.jaxb.AbstractCommonList; +import org.collectionspace.services.article.ArticlesCommon; + +import org.jboss.resteasy.client.ClientResponse; +import org.testng.Assert; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ArticleServiceTest, carries out tests against a deployed and running Articles + * Service. + * + * $LastChangedRevision$ $LastChangedDate$ + */ +public class ArticleServiceTest extends + AbstractPoxServiceTestImpl { + + /** The logger. */ + private final String CLASS_NAME = ArticleServiceTest.class.getName(); + private final Logger logger = LoggerFactory.getLogger(CLASS_NAME); + // Instance variables specific to this test. + /** The service path component. */ + final String SERVICE_NAME = "articles"; + final String SERVICE_PATH_COMPONENT = "articles"; + + /* + * (non-Javadoc) + * + * @see + * org.collectionspace.services.client.test.BaseServiceTest#getClientInstance + * () + */ + @Override + protected ArticleClient getClientInstance() { + return new ArticleClient(); + } + + /* + * (non-Javadoc) + * + * @see org.collectionspace.services.client.test.BaseServiceTest# + * getAbstractCommonList(org.jboss.resteasy.client.ClientResponse) + */ + @Override + protected AbstractCommonList getCommonList( + ClientResponse response) { + return response.getEntity(AbstractCommonList.class); + } + + // --------------------------------------------------------------- + // CRUD tests : CREATE tests + // --------------------------------------------------------------- + + // Success outcomes + + /* + * (non-Javadoc) + * + * @see + * org.collectionspace.services.client.test.ServiceTest#create(java.lang + * .String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class) + public void create(String testName) throws Exception { + // Perform setup, such as initializing the type of service request + // (e.g. CREATE, DELETE), its valid and expected status codes, and + // its associated HTTP method name (e.g. POST, DELETE). + setupCreate(); + + // Submit the request to the service and store the response. + ArticleClient client = new ArticleClient(); + String identifier = createIdentifier(); + PoxPayloadOut multipart = createArticleInstance(identifier); + String newID = null; + ClientResponse res = client.create(multipart); + try { + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + // + // Specifically: + // Does it fall within the set of valid status codes? + // Does it exactly match the expected status code? + if (logger.isDebugEnabled()) { + logger.debug(testName + ": status = " + statusCode); + } + Assert.assertTrue(testRequestType.isValidStatusCode(statusCode), + invalidStatusCodeMessage(testRequestType, statusCode)); + Assert.assertEquals(statusCode, testExpectedStatusCode); + + newID = extractId(res); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + + // Store the ID returned from the first resource created + // for additional tests below. + if (knownResourceId == null) { + knownResourceId = newID; + if (logger.isDebugEnabled()) { + logger.debug(testName + ": knownResourceId=" + knownResourceId); + } + } + + // Store the IDs from every resource created by tests, + // so they can be deleted after tests have been run. + allResourceIdsCreated.add(newID); + } + + /* + * (non-Javadoc) + * + * @see + * org.collectionspace.services.client.test.AbstractServiceTestImpl#createList + * (java.lang.String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"create"}) + public void createList(String testName) throws Exception { + for (int i = 0; i < 3; i++) { + create(testName); + } + } + + // --------------------------------------------------------------- + // CRUD tests : READ tests + // --------------------------------------------------------------- + + /* + * (non-Javadoc) + * + * @see + * org.collectionspace.services.client.test.AbstractServiceTestImpl#read + * (java.lang.String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"create"}) + public void read(String testName) throws Exception { + // Perform setup. + setupRead(); + + // Submit the request to the service and store the response. + ArticleClient client = new ArticleClient(); + ClientResponse res = client.read(knownResourceId); + PoxPayloadIn input = null; + try { + assertStatusCode(res, testName); + input = new PoxPayloadIn(res.getEntity()); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + + // Get the common part of the response and verify that it is not null. + PayloadInputPart payloadInputPart = input.getPart(client + .getCommonPartName()); + ArticlesCommon articlesCommon = null; + if (payloadInputPart != null) { + articlesCommon = (ArticlesCommon) payloadInputPart.getBody(); + } + Assert.assertNotNull(articlesCommon); + + } + + // Failure outcomes + + /* + * (non-Javadoc) + * + * @see org.collectionspace.services.client.test.AbstractServiceTestImpl# + * readNonExistent(java.lang.String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"read"}) + public void readNonExistent(String testName) throws Exception { + // Perform setup. + setupReadNonExistent(); + + // Submit the request to the service and store the response. + ArticleClient client = new ArticleClient(); + ClientResponse res = client.read(NON_EXISTENT_ID); + try { + 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(testRequestType.isValidStatusCode(statusCode), + invalidStatusCodeMessage(testRequestType, statusCode)); + Assert.assertEquals(statusCode, testExpectedStatusCode); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + } + + // --------------------------------------------------------------- + // CRUD tests : READ_LIST tests + // --------------------------------------------------------------- + + // Success outcomes + + /* + * (non-Javadoc) + * + * @see + * org.collectionspace.services.client.test.AbstractServiceTestImpl#readList + * (java.lang.String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"createList", "read"}) + public void readList(String testName) throws Exception { + // Perform setup. + setupReadList(); + + // Submit the request to the service and store the response. + AbstractCommonList list = null; + ArticleClient client = new ArticleClient(); + ClientResponse res = client.readList(); + assertStatusCode(res, testName); + try { + 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(testRequestType.isValidStatusCode(statusCode), + invalidStatusCodeMessage(testRequestType, statusCode)); + Assert.assertEquals(statusCode, testExpectedStatusCode); + + list = res.getEntity(); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + + // Optionally output additional data about list members for debugging. + boolean iterateThroughList = true; + if (iterateThroughList && logger.isDebugEnabled()) { + AbstractCommonListUtils.ListItemsInAbstractCommonList(list, logger, + testName); + } + + } + + // Failure outcomes + // None at present. + + // --------------------------------------------------------------- + // CRUD tests : UPDATE tests + // --------------------------------------------------------------- + + // Success outcomes + + /* + * (non-Javadoc) + * + * @see + * org.collectionspace.services.client.test.AbstractServiceTestImpl#update + * (java.lang.String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"read"}) + public void update(String testName) throws Exception { + // Perform setup. + setupRead(); + + // Retrieve the contents of a resource to update. + ArticleClient client = new ArticleClient(); + ClientResponse res = client.read(knownResourceId); + PoxPayloadIn input = null; + try { + assertStatusCode(res, testName); + input = new PoxPayloadIn(res.getEntity()); + if (logger.isDebugEnabled()) { + logger.debug("got object to update with ID: " + knownResourceId); + } + } finally { + if (res != null) { + res.releaseConnection(); + } + } + + // Extract the common part from the response. + PayloadInputPart payloadInputPart = input.getPart(client + .getCommonPartName()); + ArticlesCommon articlesCommon = null; + if (payloadInputPart != null) { + articlesCommon = (ArticlesCommon) payloadInputPart.getBody(); + } + Assert.assertNotNull(articlesCommon); + + // Update the content of this resource. + articlesCommon.setArticleNumber("updated-" + + articlesCommon.getArticleNumber()); + articlesCommon.setArticleJobId("updated-" + articlesCommon.getArticleJobId()); + if (logger.isDebugEnabled()) { + logger.debug("to be updated object"); + logger.debug(objectAsXmlString(articlesCommon, ArticlesCommon.class)); + } + + setupUpdate(); + + // Submit the updated common part in an update request to the service + // and store the response. + PoxPayloadOut output = new PoxPayloadOut(this.getServicePathComponent()); + PayloadOutputPart commonPart = output.addPart( + client.getCommonPartName(), articlesCommon); + res = client.update(knownResourceId, output); + try { + assertStatusCode(res, testName); + 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(testRequestType.isValidStatusCode(statusCode), + invalidStatusCodeMessage(testRequestType, statusCode)); + Assert.assertEquals(statusCode, testExpectedStatusCode); + input = new PoxPayloadIn(res.getEntity()); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + + // Extract the updated common part from the response. + payloadInputPart = input.getPart(client.getCommonPartName()); + ArticlesCommon updatedArticleCommon = null; + if (payloadInputPart != null) { + updatedArticleCommon = (ArticlesCommon) payloadInputPart.getBody(); + } + Assert.assertNotNull(updatedArticleCommon); + + // Check selected fields in the updated common part. + Assert.assertEquals(updatedArticleCommon.getArticleNumber(), + articlesCommon.getArticleNumber(), + "Data in updated object did not match submitted data."); + + if (logger.isDebugEnabled()) { + logger.debug("UTF-8 data sent=" + articlesCommon.getArticleJobId() + + "\n" + "UTF-8 data received=" + + updatedArticleCommon.getArticleJobId()); + } + Assert.assertTrue( + updatedArticleCommon.getArticleJobId().contains( + getUTF8DataFragment()), "UTF-8 data retrieved '" + + updatedArticleCommon.getArticleJobId() + + "' does not contain expected data '" + + getUTF8DataFragment()); + Assert.assertEquals(updatedArticleCommon.getArticleJobId(), + articlesCommon.getArticleJobId(), + "Data in updated object did not match submitted data."); + } + + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"update", "testSubmitRequest"}) + public void updateNonExistent(String testName) throws Exception { + // Perform setup. + setupUpdateNonExistent(); + + // Submit the request to the service and store the response. + // Note: The ID used in this 'create' call may be arbitrary. + // The only relevant ID may be the one used in update(), below. + ArticleClient client = new ArticleClient(); + PoxPayloadOut multipart = createArticleInstance(NON_EXISTENT_ID); + ClientResponse res = client.update(NON_EXISTENT_ID, multipart); + try { + 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(testRequestType.isValidStatusCode(statusCode), + invalidStatusCodeMessage(testRequestType, statusCode)); + Assert.assertEquals(statusCode, testExpectedStatusCode); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + } + + // --------------------------------------------------------------- + // CRUD tests : DELETE tests + // --------------------------------------------------------------- + + // Success outcomes + + /* + * (non-Javadoc) + * + * @see + * org.collectionspace.services.client.test.AbstractServiceTestImpl#delete + * (java.lang.String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"}) + public void delete(String testName) throws Exception { + // Perform setup. + setupDelete(); + + // Submit the request to the service and store the response. + ArticleClient client = new ArticleClient(); + ClientResponse res = client.delete(knownResourceId); + try { + 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(testRequestType.isValidStatusCode(statusCode), + invalidStatusCodeMessage(testRequestType, statusCode)); + Assert.assertEquals(statusCode, testExpectedStatusCode); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + } + + // Failure outcomes + + /* + * (non-Javadoc) + * + * @see org.collectionspace.services.client.test.AbstractServiceTestImpl# + * deleteNonExistent(java.lang.String) + */ + @Override + // @Test(dataProvider = "testName", dataProviderClass = + // AbstractServiceTestImpl.class, + // dependsOnMethods = {"delete"}) + public void deleteNonExistent(String testName) throws Exception { + // Perform setup. + setupDeleteNonExistent(); + + // Submit the request to the service and store the response. + ArticleClient client = new ArticleClient(); + ClientResponse res = client.delete(NON_EXISTENT_ID); + try { + 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(testRequestType.isValidStatusCode(statusCode), + invalidStatusCodeMessage(testRequestType, statusCode)); + Assert.assertEquals(statusCode, testExpectedStatusCode); + } finally { + if (res != null) { + res.releaseConnection(); + } + } + } + + // --------------------------------------------------------------- + // Utility tests : tests of code used in tests above + // --------------------------------------------------------------- + + /** + * Tests the code for manually submitting data that is used by several of + * the methods above. + */ + // @Test(dependsOnMethods = {"create", "read"}) + public void testSubmitRequest() { + + // Expected status code: 200 OK + final int EXPECTED_STATUS = Response.Status.OK.getStatusCode(); + + // Submit the request to the service and store the response. + String method = ServiceRequestType.READ.httpMethodName(); + String url = getResourceURL(knownResourceId); + int statusCode = submitRequest(method, url); + + // Check the status code of the response: does it match + // the expected response(s)? + if (logger.isDebugEnabled()) { + logger.debug("testSubmitRequest: url=" + url + " status=" + + statusCode); + } + Assert.assertEquals(statusCode, EXPECTED_STATUS); + + } + + // --------------------------------------------------------------- + // Utility methods used by tests above + // --------------------------------------------------------------- + + @Override + public String getServiceName() { + return SERVICE_NAME; + } + + /* + * (non-Javadoc) + * + * @see org.collectionspace.services.client.test.BaseServiceTest# + * getServicePathComponent() + */ + @Override + public String getServicePathComponent() { + return SERVICE_PATH_COMPONENT; + } + + @Override + protected PoxPayloadOut createInstance(String identifier) { + return createArticleInstance(identifier); + } + + /** + * Creates the article instance. + * + * @param identifier + * the identifier + * @return the multipart output + */ + private PoxPayloadOut createArticleInstance(String identifier) { + return createArticleInstance("loaninNumber-" + identifier, + "returnDate-" + identifier); + } + + /** + * Creates the article instance. + * + * @param loaninNumber + * the article number + * @param returnDate + * the return date + * @return the multipart output + */ + private PoxPayloadOut createArticleInstance(String articleNumber, + String articleJobId) { + + ArticlesCommon articlesCommon = new ArticlesCommon(); + articlesCommon.setArticleNumber(articleNumber); + articlesCommon.setArticleJobId(articleJobId); + + PoxPayloadOut multipart = new PoxPayloadOut( + this.getServicePathComponent()); + PayloadOutputPart commonPart = multipart.addPart( + new ArticleClient().getCommonPartName(), articlesCommon); + + if (logger.isDebugEnabled()) { + logger.debug("To be created, article common:"); + logger.debug(objectAsXmlString(articlesCommon, ArticlesCommon.class)); + } + + return multipart; + } + + @Override + public void CRUDTests(String testName) { + // TODO Auto-generated method stub + + } + + @Override + protected PoxPayloadOut createInstance(String commonPartName, + String identifier) { + PoxPayloadOut result = createArticleInstance(identifier); + return result; + } + + @Override + protected ArticlesCommon updateInstance(ArticlesCommon commonPartObject) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected void compareUpdatedInstances(ArticlesCommon original, + ArticlesCommon updated) throws Exception { + // TODO Auto-generated method stub + + } +} diff --git a/services/article/jaxb/pom.xml b/services/article/jaxb/pom.xml new file mode 100644 index 000000000..7532bd4ac --- /dev/null +++ b/services/article/jaxb/pom.xml @@ -0,0 +1,34 @@ + + + + org.collectionspace.services.article + org.collectionspace.services + 3.2.1-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.article.jaxb + services.article.jaxb + + + + org.collectionspace.services + org.collectionspace.services.jaxb + ${project.version} + + + + + collectionspace-services-article-jaxb + install + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + + + + + diff --git a/services/article/jaxb/src/main/java/org/collectionspace/services/ArticlesCommonJAXBSchema.java b/services/article/jaxb/src/main/java/org/collectionspace/services/ArticlesCommonJAXBSchema.java new file mode 100644 index 000000000..9c4c56a57 --- /dev/null +++ b/services/article/jaxb/src/main/java/org/collectionspace/services/ArticlesCommonJAXBSchema.java @@ -0,0 +1,32 @@ +/** + * String constants to access XML element names of the ArticlesCommon class. + */ +package org.collectionspace.services; + +/* + + + + + + + + + + + + + + + */ + +public interface ArticlesCommonJAXBSchema { + final static String ARTICLE_NUMBER = "articleNumber"; + final static String ARTICLE_CONTENT_URL = "articleContentUrl"; + final static String ARTICLE_JOB_ID = "articleJobId"; + final static String ARTICLE_SOURCE = "articleSource"; + final static String ARTICLE_PUBLISHER = "articlePublisher"; + final static String ARTICLE_ACCESS_EXPIRATION_DATE = "accessExpirationDate"; + final static String ARTICLE_ACCESSED_COUNT = "accessedCount"; + final static String ARTICLE_ACCESS_COUNT_LIMIT = "accessCountLimit"; +} \ No newline at end of file diff --git a/services/article/jaxb/src/main/resources/articles-common.xsd b/services/article/jaxb/src/main/resources/articles-common.xsd new file mode 100644 index 000000000..007363849 --- /dev/null +++ b/services/article/jaxb/src/main/resources/articles-common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/services/article/pom.xml b/services/article/pom.xml new file mode 100644 index 000000000..9efdae2d0 --- /dev/null +++ b/services/article/pom.xml @@ -0,0 +1,26 @@ + + + + + org.collectionspace.services + org.collectionspace.services.main + 3.2.1-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.article + services.article + pom + + + + + + jaxb + client + 3rdparty + service + + + + diff --git a/services/article/service/pom.xml b/services/article/service/pom.xml new file mode 100644 index 000000000..696554f01 --- /dev/null +++ b/services/article/service/pom.xml @@ -0,0 +1,104 @@ + + + + + org.collectionspace.services + org.collectionspace.services.article + 3.2.1-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.article.service + services.article.service + jar + + + + org.collectionspace.services + org.collectionspace.services.common + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.article.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.article.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.collectionobject.jaxb + ${project.version} + + + + junit + junit + 4.1 + test + + + org.testng + testng + + + + + + javax.security + jaas + 1.0.01 + provided + + + + dom4j + dom4j + 1.6.1 + provided + + + + + + org.jboss.resteasy + resteasy-jaxrs + + + tjws + webserver + + + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + resteasy-multipart-provider + + + + + + org.nuxeo.ecm.core + nuxeo-core-api + + + jboss-remoting + jboss + + + + + + + + collectionspace-services-article + + + diff --git a/services/article/service/profiles.xml b/services/article/service/profiles.xml new file mode 100644 index 000000000..347b9df22 --- /dev/null +++ b/services/article/service/profiles.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/services/article/service/src/main/java/org/collectionspace/services/article/ArticleResource.java b/services/article/service/src/main/java/org/collectionspace/services/article/ArticleResource.java new file mode 100644 index 000000000..168420ecf --- /dev/null +++ b/services/article/service/src/main/java/org/collectionspace/services/article/ArticleResource.java @@ -0,0 +1,72 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.article; + +import org.collectionspace.services.client.ArticleClient; +import org.collectionspace.services.common.ResourceBase; +import org.jboss.resteasy.core.ResourceMethod; +import org.jboss.resteasy.spi.HttpRequest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +@Path(ArticleClient.SERVICE_PATH) +@Consumes("application/xml") +@Produces("application/xml") +public class ArticleResource extends ResourceBase { + + final Logger logger = LoggerFactory.getLogger(ArticleResource.class); + + @Override + protected String getVersionString() { + final String lastChangeRevision = "$LastChangedRevision$"; + return lastChangeRevision; + } + + @Override + public String getServiceName() { + return ArticleClient.SERVICE_NAME; + } + + @Override + public Class getCommonPartClass() { + return ArticlesCommon.class; + } + + @Override + public boolean allowAnonymousAccess(HttpRequest request, + ResourceMethod method) { + return true; + } +} + + + + + + diff --git a/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleConstants.java b/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleConstants.java new file mode 100644 index 000000000..a645ea40f --- /dev/null +++ b/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleConstants.java @@ -0,0 +1,34 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.article.nuxeo; + +/** + * ArticleConstants specifies constants for the Articles In service + * + */ +public class ArticleConstants { + public final static String NUXEO_DOCTYPE = "Article"; + public final static String NUXEO_SCHEMA_NAME = "article"; + public final static String NUXEO_DC_TITLE = "CollectionSpace-Article"; +} diff --git a/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleDocumentModelHandler.java b/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleDocumentModelHandler.java new file mode 100644 index 000000000..45f4ae48c --- /dev/null +++ b/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleDocumentModelHandler.java @@ -0,0 +1,36 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.article.nuxeo; + +import org.collectionspace.services.article.ArticlesCommon; +import org.collectionspace.services.nuxeo.client.java.DocHandlerBase; + +/** ArticleDocumentModelHandler + * $LastChangedRevision$ + * $LastChangedDate$ + */ +public class ArticleDocumentModelHandler + extends DocHandlerBase { +} + diff --git a/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleValidatorHandler.java b/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleValidatorHandler.java new file mode 100644 index 000000000..fb42e5cb1 --- /dev/null +++ b/services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleValidatorHandler.java @@ -0,0 +1,20 @@ +package org.collectionspace.services.article.nuxeo; + +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.document.InvalidDocumentException; +import org.collectionspace.services.common.document.ValidatorHandler; +import org.collectionspace.services.common.document.DocumentHandler.Action; +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; + +public class ArticleValidatorHandler implements ValidatorHandler { + + @Override + public void validate(Action action, ServiceContext ctx) + throws InvalidDocumentException { + // TODO Auto-generated method stub + System.out.println("ArticleValidatorHandler executed."); + + } + +} diff --git a/services/article/service/src/test/java/org/collectionspace/services/test/ArticleServiceTest.java b/services/article/service/src/test/java/org/collectionspace/services/test/ArticleServiceTest.java new file mode 100644 index 000000000..56fb8901f --- /dev/null +++ b/services/article/service/src/test/java/org/collectionspace/services/test/ArticleServiceTest.java @@ -0,0 +1,13 @@ +package org.collectionspace.services.test; + +//import org.collectionspace.services.article.Article; +//import org.collectionspace.services.article.ArticleList; + +/** + * Placeholder for server-side testing of Articles service code. + * + * @version $Revision$ + */ +public class ArticleServiceTest { + //empty +} diff --git a/services/article/service/src/test/resources/log4j.xml b/services/article/service/src/test/resources/log4j.xml new file mode 100644 index 000000000..52121cb83 --- /dev/null +++ b/services/article/service/src/test/resources/log4j.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/authentication/service/src/main/java/org/collectionspace/authentication/spi/AuthNContext.java b/services/authentication/service/src/main/java/org/collectionspace/authentication/spi/AuthNContext.java index 2dc88742a..506c11fac 100644 --- a/services/authentication/service/src/main/java/org/collectionspace/authentication/spi/AuthNContext.java +++ b/services/authentication/service/src/main/java/org/collectionspace/authentication/spi/AuthNContext.java @@ -33,6 +33,12 @@ import org.collectionspace.authentication.CSpaceTenant; */ public abstract class AuthNContext { + public static final String ANONYMOUS_USER = "anonymous"; + public static final String ANONYMOUS_TENANT_ID = "-1"; + public static final String ANONYMOUS_TENANT_NAME = ANONYMOUS_USER; + public static final String SPRING_ADMIN_USER = "SPRING_ADMIN"; + public static final String TENANT_ID_QUERY_PARAM = "tid"; + /** * getUserId returns authenticated user id * @return diff --git a/services/authentication/service/src/main/java/org/collectionspace/authentication/spring/SpringAuthNContext.java b/services/authentication/service/src/main/java/org/collectionspace/authentication/spring/SpringAuthNContext.java index 27801a2b4..9094773f6 100644 --- a/services/authentication/service/src/main/java/org/collectionspace/authentication/spring/SpringAuthNContext.java +++ b/services/authentication/service/src/main/java/org/collectionspace/authentication/spring/SpringAuthNContext.java @@ -23,14 +23,17 @@ */ package org.collectionspace.authentication.spring; -import java.security.acl.Group; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Set; + +import java.security.acl.Group; import javax.security.auth.Subject; + import org.collectionspace.authentication.CSpaceTenant; import org.collectionspace.authentication.spi.AuthNContext; + import org.springframework.security.authentication.jaas.JaasAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -43,8 +46,14 @@ final public class SpringAuthNContext extends AuthNContext { //private static final String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container"; public String getUserId() { + String result = ANONYMOUS_USER; + Authentication authToken = SecurityContextHolder.getContext().getAuthentication(); - return authToken.getName(); + if (authToken != null) { + result = authToken.getName(); + } + + return result; } /** @@ -64,25 +73,31 @@ final public class SpringAuthNContext extends AuthNContext { @Override public String getCurrentTenantId() { - //FIXME assumption in 1.0: each user is associated with a single tenant - String[] tenantIds = getTenantIds(); - if (tenantIds.length < 1) { - throw new IllegalStateException("No tenant associated with user=" + getUserId()); - } - return getTenantIds()[0]; + String result = ANONYMOUS_TENANT_ID; + + String userId = getUserId(); + if (userId.equals(ANONYMOUS_USER) == false && userId.equals(SPRING_ADMIN_USER) == false) { + String[] tenantIds = getTenantIds(); + if (tenantIds.length < 1) { + throw new IllegalStateException("No tenant associated with user=" + getUserId()); + } + result = getTenantIds()[0]; + } + + return result; } public CSpaceTenant[] getTenants() { List tenants = new ArrayList(); Subject caller = getSubject(); if (caller == null) { - String msg = "Could not find Subject!"; - //TODO: find out why subject is not null - //FIXME: if logger is loaded when authn comes up, use it - //logger.warn(msg); - System.err.println(msg); + if (getUserId().equals(SPRING_ADMIN_USER) == false) { + String msg = String.format("Could not find Subject in SpringAuthNContext for user '%s'!", getUserId()); + System.err.println(msg); + } return tenants.toArray(new CSpaceTenant[0]); } + Set groups = null; groups = caller.getPrincipals(Group.class); if (groups != null && groups.size() == 0) { @@ -112,12 +127,17 @@ final public class SpringAuthNContext extends AuthNContext { @Override public String getCurrentTenantName() { - //FIXME assumption in 1.0: each user is associated with a single tenant - CSpaceTenant[] tenants = getTenants(); - if (tenants.length < 1) { - throw new IllegalStateException("No tenant associated with user=" + getUserId()); - } - return getTenants()[0].getName(); + String result = ANONYMOUS_TENANT_NAME; + + if (getUserId().equals(ANONYMOUS_USER) == false) { + CSpaceTenant[] tenants = getTenants(); + if (tenants.length < 1) { + throw new IllegalStateException("No tenant associated with user=" + getUserId()); + } + result = getTenants()[0].getName(); + } + + return result; } public Subject getSubject() { diff --git a/services/blob/client/pom.xml b/services/blob/client/pom.xml index 7d6ee4791..731192572 100644 --- a/services/blob/client/pom.xml +++ b/services/blob/client/pom.xml @@ -5,7 +5,7 @@ org.collectionspace.services org.collectionspace.services.blob - 3.2-SNAPSHOT + 3.2.1-SNAPSHOT 4.0.0 diff --git a/services/blob/pom.xml b/services/blob/pom.xml index 7eeea3a4a..153c62e04 100644 --- a/services/blob/pom.xml +++ b/services/blob/pom.xml @@ -13,9 +13,9 @@ http://www.collectionspace.org - service - 3rdparty client + 3rdparty + service diff --git a/services/collectionobject/client/pom.xml b/services/collectionobject/client/pom.xml index 2a532a5aa..fc8aad620 100644 --- a/services/collectionobject/client/pom.xml +++ b/services/collectionobject/client/pom.xml @@ -5,7 +5,7 @@ org.collectionspace.services org.collectionspace.services.collectionobject - 3.2-SNAPSHOT + 3.2.1-SNAPSHOT 4.0.0 diff --git a/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto.xml b/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto.xml index 55d687086..baae7d62c 100644 --- a/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto.xml +++ b/services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto.xml @@ -2908,6 +2908,65 @@ + + + + + default-domain + org.collectionspace.services.article.nuxeo.ArticleDocumentModelHandler + + + + + articleNumber + articleNumber + + + articleContentUrl + articleContentUrl + + + + + org.collectionspace.services.article.nuxeo.ArticleValidatorHandler + + + objectNameProperty + articleContentUrl + + + objectNumberProperty + articleNumber + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java b/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java index c85a1b8bb..c04368c1c 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java @@ -46,7 +46,9 @@ import org.collectionspace.services.common.repository.RepositoryClientFactory; import org.collectionspace.services.common.security.UnauthorizedException; import org.collectionspace.services.common.storage.StorageClient; import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl; -import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.core.ResourceMethod; +import org.jboss.resteasy.spi.HttpRequest; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -498,4 +500,10 @@ public abstract class AbstractCollectionSpaceResourceImpl return result; } + + @Override + public boolean allowAnonymousAccess(HttpRequest request, + ResourceMethod method) { + return false; + } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java index 9b8b1451b..5e34217e1 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java +++ b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java @@ -28,6 +28,8 @@ import org.collectionspace.services.common.context.ServiceContextFactory; import org.collectionspace.services.common.document.DocumentHandler; import org.collectionspace.services.common.repository.RepositoryClient; import org.collectionspace.services.common.storage.StorageClient; +import org.jboss.resteasy.core.ResourceMethod; +import org.jboss.resteasy.spi.HttpRequest; /** * The Interface CollectionSpaceResource. @@ -84,4 +86,14 @@ public interface CollectionSpaceResource { */ public ServiceContextFactory getServiceContextFactory(); + /* + * Returns true if this resource allow anonymous access. It addition to returning 'true', this + * resources base URL path needs to be declared in the Spring Security config file's 'springSecurityFilterChain' bean. + * There needs to be a 'filter-chain' element something like the following: + + * See the "applicationContext-security.xml" file for details. + */ + public boolean allowAnonymousAccess(HttpRequest request, ResourceMethod method); + } diff --git a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java index 300c0e3ad..2905214a7 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java +++ b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java @@ -123,9 +123,9 @@ public class AuthorizationCommon { public static final String DEFAULT_ADMIN_PASSWORD = "Administrator"; public static final String DEFAULT_READER_PASSWORD = "reader"; - public static String ROLE_SPRING_ADMIN_ID = "-1"; - public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN"; - + public static final String ROLE_SPRING_ADMIN_ID = "-1"; + public static final String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN"; + // SQL for init tasks final private static String INSERT_ACCOUNT_ROLE_SQL_MYSQL = "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)" diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java index 243e9ccd9..ba9388a2c 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java @@ -30,6 +30,7 @@ import java.util.Map; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriInfo; +import org.collectionspace.authentication.spi.AuthNContext; import org.collectionspace.services.client.IQueryManager; import org.collectionspace.services.client.workflow.WorkflowClient; import org.collectionspace.services.common.ServiceMain; @@ -118,15 +119,16 @@ public abstract class AbstractServiceContextImpl * * @throws UnauthorizedException the unauthorized exception */ - protected AbstractServiceContextImpl(String serviceName) throws UnauthorizedException { + protected AbstractServiceContextImpl(String serviceName, UriInfo uriInfo) throws UnauthorizedException { //establish security context - securityContext = new SecurityContextImpl(); + securityContext = new SecurityContextImpl(uriInfo); //make sure tenant context exists checkTenantContext(); String tenantId = securityContext.getCurrentTenantId(); - if(AuthorizationCommon.ALL_TENANTS_MANAGER_TENANT_ID.equals(tenantId)) { + if (AuthorizationCommon.ALL_TENANTS_MANAGER_TENANT_ID.equals(tenantId) || + AuthNContext.ANONYMOUS_TENANT_ID.equals(tenantId)) { // Tenant Manager has no tenant binding, so don't bother... tenantBinding = null; serviceBinding = null; diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextFactory.java b/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextFactory.java index 0b8df0143..c13994bca 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextFactory.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextFactory.java @@ -60,8 +60,10 @@ public class MultipartServiceContextFactory * @see org.collectionspace.services.common.context.ServiceContextFactory#createServiceContext(java.lang.String) */ @Override - public ServiceContext createServiceContext(String serviceName) throws Exception { - MultipartServiceContext ctx = new MultipartServiceContextImpl(serviceName); + public ServiceContext createServiceContext( + String serviceName, + UriInfo uriInfo) throws Exception { + MultipartServiceContext ctx = new MultipartServiceContextImpl(serviceName, uriInfo); return ctx; } @@ -70,8 +72,9 @@ public class MultipartServiceContextFactory */ @Override public ServiceContext createServiceContext(String serviceName, - PoxPayloadIn input) throws Exception { - MultipartServiceContext ctx = new MultipartServiceContextImpl(serviceName, input); + PoxPayloadIn input, + UriInfo uriInfo) throws Exception { + MultipartServiceContext ctx = new MultipartServiceContextImpl(serviceName, input, uriInfo); return ctx; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextImpl.java b/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextImpl.java index 7c786735c..3898cb85a 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextImpl.java @@ -27,7 +27,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriInfo; import org.collectionspace.services.client.PayloadInputPart; @@ -38,10 +37,7 @@ import org.collectionspace.services.common.ResourceMap; import org.collectionspace.services.common.security.UnauthorizedException; import org.dom4j.DocumentException; import org.dom4j.Element; -//import org.jboss.resteasy.plugins.providers.multipart.InputPart; -//import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; -//import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; -//import org.jboss.resteasy.plugins.providers.multipart.OutputPart; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,9 +62,10 @@ public class MultipartServiceContextImpl * * @throws UnauthorizedException the unauthorized exception */ - protected MultipartServiceContextImpl(String serviceName) + protected MultipartServiceContextImpl(String serviceName, + UriInfo uriInfo) throws DocumentException, UnauthorizedException { - super(serviceName); + super(serviceName, uriInfo); setOutput(new PoxPayloadOut(serviceName)); } @@ -79,9 +76,9 @@ public class MultipartServiceContextImpl * * @throws UnauthorizedException the unauthorized exception */ - protected MultipartServiceContextImpl(String serviceName, PoxPayloadIn theInput) + protected MultipartServiceContextImpl(String serviceName, PoxPayloadIn theInput, UriInfo uriInfo) throws DocumentException, UnauthorizedException { - super(serviceName, theInput); + super(serviceName, theInput, uriInfo); setOutput(new PoxPayloadOut(serviceName)); } diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextFactory.java b/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextFactory.java index 93272ac84..2f23e54e6 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextFactory.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextFactory.java @@ -60,8 +60,8 @@ public class RemoteServiceContextFactory * @see org.collectionspace.services.common.context.ServiceContextFactory#createServiceContext(java.lang.String) */ @Override - public ServiceContext createServiceContext(String serviceName) throws Exception { - RemoteServiceContext ctx = new RemoteServiceContextImpl(serviceName); + public ServiceContext createServiceContext(String serviceName, UriInfo uriInfo) throws Exception { + RemoteServiceContext ctx = new RemoteServiceContextImpl(serviceName, uriInfo); return ctx; } @@ -70,8 +70,8 @@ public class RemoteServiceContextFactory */ @Override public ServiceContext createServiceContext(String serviceName, - IT theInput) throws Exception { - RemoteServiceContext ctx = new RemoteServiceContextImpl(serviceName, theInput); + IT theInput, UriInfo uriInfo) throws Exception { + RemoteServiceContext ctx = new RemoteServiceContextImpl(serviceName, theInput, uriInfo); return ctx; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java b/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java index 08c932432..b0cfee337 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java @@ -76,8 +76,8 @@ public class RemoteServiceContextImpl * * @throws UnauthorizedException the unauthorized exception */ - protected RemoteServiceContextImpl(String serviceName) throws UnauthorizedException { - super(serviceName); + protected RemoteServiceContextImpl(String serviceName, UriInfo uriInfo) throws UnauthorizedException { + super(serviceName, uriInfo); } /** @@ -87,8 +87,8 @@ public class RemoteServiceContextImpl * * @throws UnauthorizedException the unauthorized exception */ - protected RemoteServiceContextImpl(String serviceName, IT theInput) throws UnauthorizedException { - this(serviceName); + protected RemoteServiceContextImpl(String serviceName, IT theInput, UriInfo uriInfo) throws UnauthorizedException { + this(serviceName, uriInfo); this.input = theInput; } @@ -105,7 +105,7 @@ public class RemoteServiceContextImpl IT theInput, ResourceMap resourceMap, UriInfo uriInfo) throws UnauthorizedException { - this(serviceName, theInput); + this(serviceName, theInput, uriInfo); this.setResourceMap(resourceMap); this.setUriInfo(uriInfo); if (uriInfo != null) { diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextFactory.java b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextFactory.java index bcc5e79a8..933426a5b 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextFactory.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextFactory.java @@ -45,7 +45,7 @@ public interface ServiceContextFactory { * * @throws Exception the exception */ - public ServiceContext createServiceContext(String serviceName, IT input) throws Exception; + public ServiceContext createServiceContext(String serviceName, IT input, UriInfo uriInfo) throws Exception; /** * Creates a new ServiceContext object. @@ -56,7 +56,7 @@ public interface ServiceContextFactory { * * @throws Exception the exception */ - public ServiceContext createServiceContext(String serviceName) throws Exception; + public ServiceContext createServiceContext(String serviceName, UriInfo uriInfo) throws Exception; /** * Creates a new ServiceContext object. diff --git a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityContextImpl.java b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityContextImpl.java index f7de2c781..ee1179482 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityContextImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityContextImpl.java @@ -27,8 +27,10 @@ */ package org.collectionspace.services.common.security; +import javax.ws.rs.core.UriInfo; + import org.collectionspace.authentication.AuthN; -import org.collectionspace.authentication.CSpaceTenant; +import org.collectionspace.authentication.spi.AuthNContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,11 +44,38 @@ public class SecurityContextImpl implements SecurityContext { private String userId; private String currentTenantName; private String currentTenantId; + + private String getTenantId(UriInfo uriInfo) throws UnauthorizedException { + String result = AuthN.get().getCurrentTenantId(); + + String userId = AuthN.get().getUserId(); + if (userId.equals(AuthNContext.ANONYMOUS_USER) == true) { + // + // If anonymous access is being attempted, then a tenant ID needs to be set as a query param + // + if (uriInfo == null) { + String errMsg = "Anonymous access attempted without a valid tenant ID query paramter. A null 'UriInfo' instance was passed into the service context constructor."; + logger.error(errMsg); + throw new UnauthorizedException(errMsg); + } + + String tenantId = uriInfo.getQueryParameters().getFirst(AuthNContext.TENANT_ID_QUERY_PARAM); + if (tenantId == null) { + String errMsg = String.format("Anonymous access to '%s' attempted without a valid tenant ID query paramter.", + uriInfo.getPath()); + logger.error(errMsg); + throw new UnauthorizedException(errMsg); + } + result = tenantId; + } + + return result; + } - public SecurityContextImpl() { + public SecurityContextImpl(UriInfo uriInfo) throws UnauthorizedException { userId = AuthN.get().getUserId(); - currentTenantId = AuthN.get().getCurrentTenantId(); - currentTenantName = AuthN.get().getCurrentTenantName(); + currentTenantId = getTenantId(uriInfo); + currentTenantName = AuthN.get().getCurrentTenantName(); } @Override 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 0b8c18393..49752e485 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 @@ -47,14 +47,17 @@ import javax.security.auth.login.LoginException; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import javax.ws.rs.ext.Provider; + import org.collectionspace.authentication.AuthN; import org.collectionspace.services.authorization.AuthZ; import org.collectionspace.services.authorization.CSpaceResource; import org.collectionspace.services.authorization.URIResourceImpl; import org.collectionspace.services.client.workflow.WorkflowClient; +import org.collectionspace.services.common.CollectionSpaceResource; 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; @@ -85,13 +88,52 @@ public class SecurityInterceptor implements PreProcessInterceptor, PostProcessIn private static final String ERROR_NUXEO_LOGOUT = "Attempt to logout when Nuxeo login context was null"; private static final String ERROR_UNBALANCED_LOGINS = "The number of Logins vs Logouts to the Nuxeo framework was unbalanced."; + private boolean implementsInterface(Class clazz, Class interfaze) { + boolean result = false; + + Class[] interfaces = clazz.getInterfaces(); + for (Class interfaceItem : interfaces) { + if (interfaceItem.equals(interfaze)) { + result = true; + break; + } + } + + return result; + } + + private boolean isAnonymousRequest(HttpRequest request, ResourceMethod resourceMethod) { + boolean result = false; + + Class resourceClass = resourceMethod.getResourceClass(); + try { + CollectionSpaceResource resourceInstance = (CollectionSpaceResource)resourceClass.newInstance(); + result = resourceInstance.allowAnonymousAccess(request, resourceMethod); + } catch (InstantiationException e) { + logger.error("isAnonymousRequest: ", e); + } catch (IllegalAccessException e) { + logger.error("isAnonymousRequest: ", e); + } + return result; + } + /* (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) + public ServerResponse preProcess(HttpRequest request, ResourceMethod resourceMethod) throws Failure, WebApplicationException { + ServerResponse result = null; // A null value essentially means success for this method + + if (isAnonymousRequest(request, resourceMethod) == true) { + // We don't need to check credentials for anonymous requests. Just login to Nuxeo and + // exit + nuxeoPreProcess(request, resourceMethod); + + return result; + } + final String servicesResource = "/cspace-services/"; // HACK - this is configured in war final int servicesResourceLen = servicesResource.length(); String httpMethod = request.getHttpMethod(); @@ -151,7 +193,7 @@ public class SecurityInterceptor implements PreProcessInterceptor, PostProcessIn // // Login to Nuxeo // - nuxeoPreProcess(request, method); + nuxeoPreProcess(request, resourceMethod); // // We've passed all the checks. Now just log the results @@ -163,7 +205,7 @@ public class SecurityInterceptor implements PreProcessInterceptor, PostProcessIn } } - return null; + return result; } @Override @@ -228,7 +270,7 @@ public class SecurityInterceptor implements PreProcessInterceptor, PostProcessIn // // Nuxeo login support // - public ServerResponse nuxeoPreProcess(HttpRequest arg0, ResourceMethod arg1) + public ServerResponse nuxeoPreProcess(HttpRequest request, ResourceMethod resourceMethod) throws Failure, WebApplicationException { try { nuxeoLogin(); diff --git a/services/common/src/main/java/org/collectionspace/services/common/servlet/PublishedResourcesServlet.java b/services/common/src/main/java/org/collectionspace/services/common/servlet/PublishedResourcesServlet.java new file mode 100644 index 000000000..d272bc9ef --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/servlet/PublishedResourcesServlet.java @@ -0,0 +1,108 @@ +package org.collectionspace.services.common.servlet; + +import java.io.IOException; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Servlet implementation class HelloServlet + */ +public class PublishedResourcesServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + /** + * @see HttpServlet#HttpServlet() + */ + public PublishedResourcesServlet() { + super(); + } + + /** + * @see Servlet#init(ServletConfig) + */ + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + /** + * @see Servlet#destroy() + */ + public void destroy() { + super.destroy(); + } + + /** + * @see Servlet#getServletConfig() + */ + public ServletConfig getServletConfig() { + return super.getServletConfig(); + } + + /** + * @see Servlet#getServletInfo() + */ + public String getServletInfo() { + return super.getServletInfo(); + } + + /** + * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response) + */ + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.service(request, response); + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) + */ + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + //super.doGet(request, response); + response.setStatus(200); + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.doPost(request, response); + } + + /** + * @see HttpServlet#doPut(HttpServletRequest, HttpServletResponse) + */ + protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.doPut(request, response); + } + + /** + * @see HttpServlet#doDelete(HttpServletRequest, HttpServletResponse) + */ + protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.doDelete(request, response); + } + + /** + * @see HttpServlet#doHead(HttpServletRequest, HttpServletResponse) + */ + protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.doHead(request, response); + } + + /** + * @see HttpServlet#doOptions(HttpServletRequest, HttpServletResponse) + */ + protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.doOptions(request, response); + } + + /** + * @see HttpServlet#doTrace(HttpServletRequest, HttpServletResponse) + */ + protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.doTrace(request, response); + } + +} diff --git a/services/pom.xml b/services/pom.xml index 46795142e..59966d278 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -71,11 +71,12 @@ contact workflow media - JaxRsServiceProvider + article IntegrationTests PerformanceTests security + JaxRsServiceProvider