]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5564: Added anonymous access Article service.
authorRichard Millet <remillet@berkeley.edu>
Sat, 19 Jan 2013 18:39:33 +0000 (10:39 -0800)
committerRichard Millet <remillet@berkeley.edu>
Sat, 19 Jan 2013 18:39:33 +0000 (10:39 -0800)
46 files changed:
pom.xml
services/JaxRsServiceProvider/pom.xml
services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java
services/JaxRsServiceProvider/src/main/webapp/WEB-INF/applicationContext-security.xml
services/JaxRsServiceProvider/src/main/webapp/WEB-INF/web.xml
services/article/3rdparty/build.xml [new file with mode: 0644]
services/article/3rdparty/nuxeo-platform-cs-article/build.xml [new file with mode: 0644]
services/article/3rdparty/nuxeo-platform-cs-article/pom.xml [new file with mode: 0644]
services/article/3rdparty/nuxeo-platform-cs-article/src/main/resources/schemas/articles_common.xsd [new file with mode: 0644]
services/article/3rdparty/pom.xml [new file with mode: 0644]
services/article/build.xml [new file with mode: 0644]
services/article/client/pom.xml [new file with mode: 0644]
services/article/client/src/main/java/org/collectionspace/services/client/ArticleClient.java [new file with mode: 0644]
services/article/client/src/main/java/org/collectionspace/services/client/ArticleProxy.java [new file with mode: 0644]
services/article/client/src/test/java/org/collectionspace/services/client/test/ArticleServiceTest.java [new file with mode: 0644]
services/article/jaxb/pom.xml [new file with mode: 0644]
services/article/jaxb/src/main/java/org/collectionspace/services/ArticlesCommonJAXBSchema.java [new file with mode: 0644]
services/article/jaxb/src/main/resources/articles-common.xsd [new file with mode: 0644]
services/article/pom.xml [new file with mode: 0644]
services/article/service/pom.xml [new file with mode: 0644]
services/article/service/profiles.xml [new file with mode: 0644]
services/article/service/src/main/java/org/collectionspace/services/article/ArticleResource.java [new file with mode: 0644]
services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleConstants.java [new file with mode: 0644]
services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleDocumentModelHandler.java [new file with mode: 0644]
services/article/service/src/main/java/org/collectionspace/services/article/nuxeo/ArticleValidatorHandler.java [new file with mode: 0644]
services/article/service/src/test/java/org/collectionspace/services/test/ArticleServiceTest.java [new file with mode: 0644]
services/article/service/src/test/resources/log4j.xml [new file with mode: 0644]
services/authentication/service/src/main/java/org/collectionspace/authentication/spi/AuthNContext.java
services/authentication/service/src/main/java/org/collectionspace/authentication/spring/SpringAuthNContext.java
services/blob/client/pom.xml
services/blob/pom.xml
services/collectionobject/client/pom.xml
services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto.xml
services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java
services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java
services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextFactory.java
services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextFactory.java
services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/context/ServiceContextFactory.java
services/common/src/main/java/org/collectionspace/services/common/security/SecurityContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java
services/common/src/main/java/org/collectionspace/services/common/servlet/PublishedResourcesServlet.java [new file with mode: 0644]
services/pom.xml

diff --git a/pom.xml b/pom.xml
index 98a49c1d91ca4d97ddfb38c9c578bce91c65444a..24201912f811e7c39154654a10f70d14e341c134 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                                <plugin>\r
                                        <groupId>org.apache.maven.plugins</groupId>\r
                                        <artifactId>maven-war-plugin</artifactId>\r
-                                       <version>2.0</version>\r
+                                       <version>2.1.1</version>\r
                                        <configuration>\r
                                                <warSourceExcludes>WEB-INF/lib/*.jar</warSourceExcludes>\r
                                                <archive>\r
index 79de463d1b61ba9b237a3e6304e3d4e1913a4109..c5bdd1591518a397a66b4e372232bc33b96d6e01 100644 (file)
@@ -31,6 +31,7 @@
             <groupId>log4j</groupId>\r
             <artifactId>log4j</artifactId>\r
             <version>1.2.14</version>\r
+            <scope>provided</scope>\r
         </dependency>\r
         <!-- somewhere dependency is added 1.5.8 unnecessarily -->\r
         <dependency>\r
             <artifactId>org.collectionspace.services.dimension.service</artifactId>\r
             <version>${project.version}</version>\r
         </dependency>\r
+        <dependency>\r
+            <groupId>org.collectionspace.services</groupId>\r
+            <artifactId>org.collectionspace.services.article.service</artifactId>\r
+            <version>${project.version}</version>\r
+        </dependency>\r
         <dependency>\r
             <groupId>org.collectionspace.services</groupId>\r
             <artifactId>org.collectionspace.services.servicegroup.service</artifactId>\r
         <dependency>\r
                        <artifactId>servlet-api</artifactId>\r
                        <groupId>javax.servlet</groupId>\r
-                       <version>2.5</version>\r
                        <scope>provided</scope>\r
         </dependency>\r
 \r
         <dependency>\r
             <groupId>org.nuxeo.ecm.core</groupId>\r
             <artifactId>nuxeo-core-api</artifactId>\r
-                       <version>${nuxeo.core.version}</version>            \r
         </dependency>\r
         <dependency>\r
             <groupId>org.nuxeo.ecm.core</groupId>\r
             <plugin>\r
                 <groupId>org.codehaus.mojo</groupId>\r
                 <artifactId>properties-maven-plugin</artifactId>\r
-                <version>1.0-alpha-2</version>\r
                 <executions>\r
                     <execution>\r
                         <phase>initialize</phase>\r
             <plugin>\r
                 <groupId>org.apache.maven.plugins</groupId>\r
                 <artifactId>maven-war-plugin</artifactId>\r
-                <version>2.1.1</version>\r
                 <configuration>\r
                     <webResources>\r
                         <resource>\r
index f2e3aca030ec4b7b9752ae5998368425913923d7..33638e96398c4e94e1c9864ea82c51315745bb92 100644 (file)
@@ -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<Class<?>> getClasses() {
         return empty;
index da685eea23bde9cd71aaf8265daac3c14e46fc71..b00593d77f0fde9ab1ef982d8a84ca1a6565c48f 100644 (file)
         org.apache.catalina.core
         org.springframework.security
     -->
-
+       
     <bean id="springSecurityFilterChain"
           class="org.springframework.security.web.FilterChainProxy">
         <sec:filter-chain-map path-type="ant">
+                       <!-- Exclude the "PublishedResourcesServlet" paths from AuthN and AuthZ.  Let's us publish resources with anonymous access. -->
+                       <sec:filter-chain pattern="/articles/**"
+                              filters="none"/>
             <sec:filter-chain pattern="/**"
                               filters="securityContextPersistenceFilter,basicAuthenticationFilter,logoutFilter,exTranslationFilter,filterInvocationInterceptor"/>
         </sec:filter-chain-map>
     </bean>
+       
 
     <bean id="securityContextPersistenceFilter"
           class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
index 2bd365af98aac66e2bff12b3f7541031ddb70f11..4515cb1f7c06a280143be090c77be9d2ac632536 100644 (file)
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">    \r
     <display-name>CollectionSpace Services</display-name>\r
        \r
+    <!-- \r
     <login-config>\r
         <auth-method>BASIC</auth-method>\r
         <realm-name>CollectionSpace realm</realm-name>\r
     </login-config>\r
+     -->\r
 \r
        <env-entry>\r
         <description>Sets the logging context for the Tiger web-app</description>\r
@@ -57,6 +59,7 @@
                <filter-name>CSpaceFilter</filter-name>\r
         <filter-class>org.collectionspace.services.common.profile.CSpaceFilter</filter-class>\r
        </filter>\r
+       \r
        <filter-mapping>\r
                <filter-name>CSpaceFilter</filter-name>\r
                <url-pattern>/*</url-pattern>\r
             <servlet-class>\r
                 org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher\r
             </servlet-class>\r
-    </servlet>\r
-    \r
+    </servlet>    \r
     <servlet-mapping>\r
         <servlet-name>Resteasy</servlet-name>\r
         <url-pattern>/*</url-pattern>\r
     </servlet-mapping>\r
+    \r
+    <servlet>\r
+            <servlet-name>PublishedResourcesServlet</servlet-name>\r
+            <servlet-class>\r
+                org.collectionspace.services.common.servlet.PublishedResourcesServlet\r
+            </servlet-class>\r
+    </servlet>    \r
+    <servlet-mapping>\r
+        <servlet-name>PublishedResourcesServlet</servlet-name>\r
+        <url-pattern>/published/*</url-pattern>\r
+    </servlet-mapping>\r
 \r
 </web-app>\r
diff --git a/services/article/3rdparty/build.xml b/services/article/3rdparty/build.xml
new file mode 100644 (file)
index 0000000..35a6ae2
--- /dev/null
@@ -0,0 +1,127 @@
+
+<project name="article.3rdparty" default="package" basedir=".">
+    <description>
+        article service 3rdparty
+    </description>
+  <!-- set global properties for this build -->
+    <property name="services.trunk" value="../../.."/>
+    <!-- enviornment should be declared before reading build.properties -->
+    <property environment="env" />
+    <property file="${services.trunk}/build.properties" />
+    <property name="mvn.opts" value="" />
+    <property name="src" location="src"/>
+
+    <condition property="osfamily-unix">
+        <os family="unix" />
+    </condition>
+    <condition property="osfamily-windows">
+        <os family="windows" />
+    </condition>
+
+    <target name="init" >
+    <!-- Create the time stamp -->
+        <tstamp/>
+    </target>
+
+    <target name="package" depends="package-unix,package-windows"
+  description="Package CollectionSpace Services" />
+    <target name="package-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="package" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="package-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="package" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="install" depends="install-unix,install-windows"
+  description="Install" />
+    <target name="install-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="install" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="install-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="install" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    
+    <target name="clean" depends="clean-unix,clean-windows"
+  description="Delete target directories" >
+        <delete dir="${build}"/>
+    </target>
+    <target name="clean-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="clean" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="clean-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="clean" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="test" depends="test-unix,test-windows" description="Run tests" />
+    <target name="test-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="test" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="test-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="test" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="deploy" depends="install"
+    description="deploy article in ${jee.server.nuxeo}">
+        <ant antfile="nuxeo-platform-cs-article/build.xml" target="deploy" inheritall="false"/>
+    </target>
+
+    <target name="undeploy"
+    description="undeploy article from ${jee.server.nuxeo}">
+        <ant antfile="nuxeo-platform-cs-article/build.xml" target="undeploy" inheritall="false"/>
+    </target>
+
+    <target name="dist"
+    description="generate distribution for article" depends="package">
+        <ant antfile="nuxeo-platform-cs-article/build.xml" target="dist" inheritall="false"/>
+    </target>
+
+
+</project>
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 (file)
index 0000000..7aa3ce5
--- /dev/null
@@ -0,0 +1,138 @@
+
+<project name="nuxeo-platform-cs-article" default="package" basedir=".">
+    <description>
+        article nuxeo document type
+    </description>
+    <!-- set global properties for this build -->
+    <property name="services.trunk" value="../../../.."/>
+    <!-- environment should be declared before reading build.properties -->
+    <property environment="env" />
+    <property file="${services.trunk}/build.properties" />
+    <property name="mvn.opts" value="" />
+    <property name="src" location="src"/>
+    <property name="nuxeo.article.jar"
+        value="org.collectionspace.services.article.3rdparty.nuxeo-${cspace.release}.jar"/>
+    <property name="nuxeo.article.jars.all"
+        value="org.collectionspace.services.article.3rdparty.nuxeo-*.jar"/>
+
+    <condition property="osfamily-unix">
+        <os family="unix" />
+    </condition>
+    <condition property="osfamily-windows">
+        <os family="windows" />
+    </condition>
+
+    <target name="init" >
+        <!-- Create the time stamp -->
+        <tstamp/>
+    </target>
+
+    <target name="package" depends="package-unix,package-windows"
+        description="Package CollectionSpace Services" />
+    <target name="package-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="package" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="package-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="package" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="install" depends="install-unix,install-windows"
+        description="Install" />
+    <target name="install-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="install" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="install-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="install" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="clean" depends="clean-unix,clean-windows"
+        description="Delete target directories" >
+        <delete dir="${build}"/>
+    </target>
+    <target name="clean-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="clean" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="clean-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="clean" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="test" depends="test-unix,test-windows" description="Run tests" />
+    <target name="test-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="test" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="test-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="test" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="deploy" depends="install"
+        description="deploy article doctype in ${jee.server.nuxeo}">
+        <copy file="${basedir}/target/${nuxeo.article.jar}"
+        todir="${jee.deploy.nuxeo.plugins}"/>
+    </target>
+
+    <target name="undeploy"
+        description="undeploy article doctype from ${jee.server.nuxeo}">
+        <delete>
+            <fileset dir="${jee.deploy.nuxeo.plugins}">
+                <include name="${nuxeo.article.jars.all}"/>
+            </fileset>
+        </delete>
+    </target>
+
+    <target name="dist"
+        description="generate distribution for article doctype" depends="package">
+        <copy todir="${services.trunk}/${dist.deploy.nuxeo.plugins}">
+            <fileset file="${basedir}/target/${nuxeo.article.jar}"/>
+        </copy>
+    </target>
+
+</project>
+
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 (file)
index 0000000..65328ea
--- /dev/null
@@ -0,0 +1,56 @@
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+        <groupId>org.collectionspace.services</groupId>
+        <artifactId>org.collectionspace.services.article.3rdparty</artifactId>
+        <version>3.2.1-SNAPSHOT</version>
+    </parent>
+    
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.collectionspace.services</groupId>
+    <artifactId>org.collectionspace.services.article.3rdparty.nuxeo</artifactId>
+    <name>services.article.3rdparty.nuxeo</name>
+    <packaging>jar</packaging>
+    <description>
+        Article Nuxeo Document Type
+    </description>
+    
+    <properties>
+        <ServiceName>article</ServiceName>
+        <NuxeoDocTypeName>Article</NuxeoDocTypeName>
+        <CommonSchemaName>articles_common</CommonSchemaName>
+               <Lifecycle>cs_default</Lifecycle>
+    </properties>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+            <resource>
+                <directory>../../../../3rdparty/nuxeo/nuxeo-doctype/src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile>
+                        <manifestEntries>
+                            <Bundle-Version>${eclipseVersion}</Bundle-Version>
+                            <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
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 (file)
index 0000000..479da46
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+    ArticlesCommon XML Schema (XSD) for Nuxeo
+    
+    Entity  : ArticlesCommon
+    Used for: Nuxeo EP core document type
+
+    $LastChangedRevision$
+    $LastChangedDate$
+-->
+
+<xs:schema 
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"
+    xmlns:ns="http://collectionspace.org/article/"
+    xmlns="http://collectionspace.org/article/"
+    targetNamespace="http://collectionspace.org/article/"
+    version="0.1">
+    
+               <xs:element name="articleNumber" type="xs:string"/>                             <!-- An ID for the article (different than the CSID) -->
+               <xs:element name="articleContentUrl" type="xs:string"/>                 <!-- The URL of the article's content -->
+               <xs:element name="articleJobId" type="xs:string"/>                              <!-- The asynch job ID -if any -->
+               <xs:element name="articleSource" type="xs:string"/>                             <!-- The name of the service/resource that was used to create the article. -->
+               <xs:element name="articlePublisher" type="xs:string"/>                  <!-- The user who published the article -->     
+               <xs:element name="accessExpirationDate" type="xs:dateTime"/>    <!-- When the article is no longer available for access -->
+               <xs:element name="accessedCount" type="xs:integer"/>                    <!-- How many times the article has been accessed. -->
+               <xs:element name="accessCountLimit" type="xs:integer"/>                 <!-- The maximum times the article can be accessed. -->
+</xs:schema>
diff --git a/services/article/3rdparty/pom.xml b/services/article/3rdparty/pom.xml
new file mode 100644 (file)
index 0000000..d1e47f2
--- /dev/null
@@ -0,0 +1,24 @@
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>org.collectionspace.services.article</artifactId>
+        <groupId>org.collectionspace.services</groupId>
+        <version>3.2.1-SNAPSHOT</version>
+    </parent>
+    
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.collectionspace.services</groupId>
+    <artifactId>org.collectionspace.services.article.3rdparty</artifactId>
+    <name>services.article.3rdparty</name>
+    <packaging>pom</packaging>
+    
+    <description>
+        3rd party build for article service
+    </description>
+
+    <modules>
+        <module>nuxeo-platform-cs-article</module>
+    </modules>
+</project>
diff --git a/services/article/build.xml b/services/article/build.xml
new file mode 100644 (file)
index 0000000..bfcb211
--- /dev/null
@@ -0,0 +1,124 @@
+
+<project name="article" default="package" basedir=".">
+    <description>
+        article service
+    </description>
+  <!-- set global properties for this build -->
+    <property name="services.trunk" value="../.."/>
+    <!-- enviornment should be declared before reading build.properties -->
+    <property environment="env" />
+    <property file="${services.trunk}/build.properties" />
+    <property name="mvn.opts" value="" />
+    <property name="src" location="src"/>
+
+    <condition property="osfamily-unix">
+        <os family="unix" />
+    </condition>
+    <condition property="osfamily-windows">
+        <os family="windows" />
+    </condition>
+
+    <target name="package" depends="package-unix,package-windows"
+  description="Package CollectionSpace Services" />
+  
+    <target name="package-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="package" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    
+    <target name="package-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="package" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+
+    <target name="install" depends="install-unix,install-windows"
+  description="Install" />
+    <target name="install-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="install" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="install-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="install" />
+            <arg value="-Dmaven.test.skip=true" />
+            <arg value="-f" />
+            <arg value="${basedir}/pom.xml" />
+            <arg value="-N" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="clean" depends="clean-unix,clean-windows"
+  description="Delete target directories" >
+        <delete dir="${build}"/>
+    </target>
+    <target name="clean-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="clean" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="clean-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="clean" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="test" depends="test-unix,test-windows" description="Run tests" />
+    <target name="test-unix" if="osfamily-unix">
+        <exec executable="mvn" failonerror="true">
+            <arg value="test" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+    <target name="test-windows" if="osfamily-windows">
+        <exec executable="cmd" failonerror="true">
+            <arg value="/c" />
+            <arg value="mvn.bat" />
+            <arg value="test" />
+            <arg value="${mvn.opts}" />
+        </exec>
+    </target>
+
+    <target name="deploy" depends="install"
+    description="deploy article service">
+        <ant antfile="3rdparty/build.xml" target="deploy" inheritall="false"/>
+    </target>
+
+    <target name="undeploy"
+    description="undeploy article service">
+        <ant antfile="3rdparty/build.xml" target="undeploy" inheritall="false"/>
+    </target>
+
+    <target name="dist" depends="package"
+    description="distribute article service">
+        <ant antfile="3rdparty/build.xml" target="dist" inheritall="false"/>
+    </target>
+
+</project>
diff --git a/services/article/client/pom.xml b/services/article/client/pom.xml
new file mode 100644 (file)
index 0000000..056998e
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <groupId>org.collectionspace.services</groupId>
+        <artifactId>org.collectionspace.services.article</artifactId>
+        <version>3.2.1-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.collectionspace.services</groupId>
+    <artifactId>org.collectionspace.services.article.client</artifactId>
+    <name>services.article.client</name>
+    
+    <dependencies>
+        <!-- keep slf4j dependencies on the top -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>test</scope>
+        </dependency>
+<!-- CollectionSpace dependencies -->
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.common</artifactId>
+            <optional>true</optional>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+         <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.article.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.person.client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.authority.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>    
+<!-- External dependencies -->        
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <!-- filter out unwanted jars -->
+            <exclusions>
+                <exclusion>
+                    <groupId>tjws</groupId>
+                    <artifactId>webserver</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxb-provider</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-multipart-provider</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.1</version>
+        </dependency>
+    </dependencies>
+    
+    <build>
+        <finalName>collectionspace-services-article-client</finalName>
+    </build>
+</project>
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 (file)
index 0000000..403ab93
--- /dev/null
@@ -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<ArticleProxy> {
+
+    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<ArticleProxy> 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 (file)
index 0000000..d5f8dea
--- /dev/null
@@ -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 (file)
index 0000000..9a87e87
--- /dev/null
@@ -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<AbstractCommonList, ArticlesCommon> {
+
+       /** 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<AbstractCommonList> 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<Response> 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<String> 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<String> 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<AbstractCommonList> 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<String> 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<String> 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<Response> 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<Response> 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 (file)
index 0000000..7532bd4
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>org.collectionspace.services.article</artifactId>
+        <groupId>org.collectionspace.services</groupId>
+        <version>3.2.1-SNAPSHOT</version>
+    </parent>
+    
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>org.collectionspace.services.article.jaxb</artifactId>
+    <name>services.article.jaxb</name>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>        
+    </dependencies>
+    
+    <build>
+        <finalName>collectionspace-services-article-jaxb</finalName>
+        <defaultGoal>install</defaultGoal>
+        <plugins>
+            <plugin>
+                <groupId>org.jvnet.jaxb2.maven2</groupId>
+                <artifactId>maven-jaxb2-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
+
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 (file)
index 0000000..9c4c56a
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * String constants to access XML element names of the ArticlesCommon class.
+ */
+package org.collectionspace.services;
+
+/*
+       <xs:element name="articles_common">
+               <xs:complexType>
+                       <xs:sequence>
+                               <xs:element name="articleNumber" type="xs:string" />                    <!-- An ID for the article (different than the CSID) -->
+                               <xs:element name="articleContentUrl" type="xs:string" />                <!-- The URL of the article's content -->
+                               <xs:element name="articleJobId" type="xs:string" />                             <!-- The asynch job ID -if any -->
+                               <xs:element name="articleSource" type="xs:string" />                    <!-- The name of the service/resource that was used to create the article. -->
+                               <xs:element name="articlePublisher" type="xs:string" />                 <!-- The user who published the article -->
+                               <xs:element name="accessExpirationDate" type="xs:dateTime" />   <!-- When the article is no longer available for access -->
+                               <xs:element name="accessedCount" type="xs:integer" />                   <!-- How many times the article has been accessed. -->
+                               <xs:element name="accessCountLimit" type="xs:integer" />                <!-- The maximum times the article can be accessed. -->
+                       </xs:sequence>
+               </xs:complexType>
+       </xs:element>
+ */
+
+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 (file)
index 0000000..0073638
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+
+<!-- ArticlesCommon XML Schema (XSD) Entity : ArticlesCommon Used for: JAXB 
+       binding between XML and Java objects $LastChangedRevision$ $LastChangedDate$ -->
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+       xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="1.0"
+       elementFormDefault="unqualified" xmlns:ns="http://collectionspace.org/services/article"
+       xmlns="http://collectionspace.org/services/article" targetNamespace="http://collectionspace.org/services/article"
+       version="0.1">
+
+       <!-- Avoid XmlRootElement nightmare: See http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html -->
+       <xs:element name="articles_common">
+               <xs:complexType>
+                       <xs:sequence>
+                               <xs:element name="articleNumber" type="xs:string" />                    <!-- An ID for the article (different than the CSID) -->
+                               <xs:element name="articleContentUrl" type="xs:string" />                <!-- The URL of the article's content -->
+                               <xs:element name="articleJobId" type="xs:string" />                             <!-- The asynch job ID -if any -->
+                               <xs:element name="articleSource" type="xs:string" />                    <!-- The name of the service/resource that was used to create the article. -->
+                               <xs:element name="articlePublisher" type="xs:string" />                 <!-- The user who published the article -->
+                               <xs:element name="accessExpirationDate" type="xs:dateTime" />   <!-- When the article is no longer available for access -->
+                               <xs:element name="accessedCount" type="xs:integer" />                   <!-- How many times the article has been accessed. -->
+                               <xs:element name="accessCountLimit" type="xs:integer" />                <!-- The maximum times the article can be accessed. -->
+                       </xs:sequence>
+               </xs:complexType>
+       </xs:element>
+
+</xs:schema>
\ No newline at end of file
diff --git a/services/article/pom.xml b/services/article/pom.xml
new file mode 100644 (file)
index 0000000..9efdae2
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- A comment. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <groupId>org.collectionspace.services</groupId>
+        <artifactId>org.collectionspace.services.main</artifactId>
+        <version>3.2.1-SNAPSHOT</version>
+    </parent>
+    
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>org.collectionspace.services.article</artifactId>
+    <name>services.article</name>
+    <packaging>pom</packaging>
+
+    <dependencies>
+    </dependencies>
+
+    <modules>
+        <module>jaxb</module>
+        <module>client</module>
+        <module>3rdparty</module>
+        <module>service</module>
+    </modules>
+
+</project>
+
diff --git a/services/article/service/pom.xml b/services/article/service/pom.xml
new file mode 100644 (file)
index 0000000..696554f
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+        <groupId>org.collectionspace.services</groupId>
+        <artifactId>org.collectionspace.services.article</artifactId>        
+        <version>3.2.1-SNAPSHOT</version>
+    </parent>
+    
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>org.collectionspace.services.article.service</artifactId>
+    <name>services.article.service</name>
+    <packaging>jar</packaging>       
+
+    <dependencies>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.article.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.article.client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.collectionobject.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!-- External dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+        </dependency>
+        
+      <!-- javax -->
+
+        <dependency>
+            <groupId>javax.security</groupId>
+            <artifactId>jaas</artifactId>
+            <version>1.0.01</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+            <scope>provided</scope>
+        </dependency>
+        
+        <!-- jboss -->
+
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>tjws</groupId>
+                    <artifactId>webserver</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxb-provider</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-multipart-provider</artifactId>
+        </dependency>
+        
+        <!-- nuxeo -->
+
+        <dependency>
+            <groupId>org.nuxeo.ecm.core</groupId>
+            <artifactId>nuxeo-core-api</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>jboss-remoting</artifactId>
+                    <groupId>jboss</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+    </dependencies>
+    
+    <build>
+        <finalName>collectionspace-services-article</finalName>
+    </build>
+</project>
+
diff --git a/services/article/service/profiles.xml b/services/article/service/profiles.xml
new file mode 100644 (file)
index 0000000..347b9df
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<profilesXml xmlns="http://maven.apache.org/PROFILES/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/PROFILES/1.0.0 http://maven.apache.org/xsd/profiles-1.0.0.xsd">
+</profilesXml>
\ 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 (file)
index 0000000..168420e
--- /dev/null
@@ -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<ArticlesCommon> 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 (file)
index 0000000..a645ea4
--- /dev/null
@@ -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 (file)
index 0000000..45f4ae4
--- /dev/null
@@ -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<ArticlesCommon> {
+}
+
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 (file)
index 0000000..fb42e5c
--- /dev/null
@@ -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<PoxPayloadIn, PoxPayloadOut> {
+
+       @Override
+       public void validate(Action action, ServiceContext<PoxPayloadIn, PoxPayloadOut> 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 (file)
index 0000000..56fb890
--- /dev/null
@@ -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 (file)
index 0000000..52121cb
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+       <appender name="console" class="org.apache.log4j.ConsoleAppender">
+               <param name="Target" value="System.out" />
+               <layout class="org.apache.log4j.TTCCLayout">
+                       <param name="DateFormat" value="ISO8601" />
+               </layout>
+       </appender>
+
+
+       <appender name="unit-tests"
+               class="org.apache.log4j.RollingFileAppender">
+               <param name="File" value="./target/unit-tests.log" />
+               <param name="MaxFileSize" value="10240KB" />
+               <param name="MaxBackupIndex" value="6" />
+               <layout class="org.apache.log4j.TTCCLayout">
+                       <param name="DateFormat" value="ISO8601" />
+               </layout>
+       </appender>
+
+       <logger name="org.apache.commons.httpclient" additivity="false">
+               <level value="warn" />
+               <appender-ref ref="console" />
+               <appender-ref ref="unit-tests" />
+       </logger>
+
+       <logger name="httpclient.wire" additivity="false">
+               <level value="info" />
+               <appender-ref ref="console" />
+               <appender-ref ref="unit-tests" />
+       </logger>
+
+       <root>
+               <priority value="debug" />
+               <appender-ref ref="console" />
+               <appender-ref ref="unit-tests" />
+       </root>
+
+</log4j:configuration>
+
+
+
+
index 2dc88742acb72bc303358de00300abcd9e6bf9e5..506c11fac2adabef1717d3a57d2b7caa469d9408 100644 (file)
@@ -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
index 27801a2b41f4882ded1549618334b6ca9c5d1a8f..9094773f6344ce074a3193c8555164184be3cf45 100644 (file)
  */
 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<CSpaceTenant> tenants = new ArrayList<CSpaceTenant>();
         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<Group> 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() {
index 7d6ee47918617fc89d7d3f6d327376289d6991c7..731192572d7715472583accef85eb1c462bdf167 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.collectionspace.services</groupId>
         <artifactId>org.collectionspace.services.blob</artifactId>
-        <version>3.2-SNAPSHOT</version>
+        <version>3.2.1-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index 7eeea3a4a81092fb9e65cdaa36a09176c94425cc..153c62e043136a0c681760d5e5b2bbef3b1c9818 100644 (file)
@@ -13,9 +13,9 @@
     <url>http://www.collectionspace.org</url>
     
     <modules>
-        <module>service</module>
-        <module>3rdparty</module>
         <module>client</module>
+        <module>3rdparty</module>
+        <module>service</module>
     </modules>
 
 </project>
index 2a532a5aa1031a0c913ffc1198974bee55391331..fc8aad620da5d64ddda79c0a38c4f5dffa2b13ba 100644 (file)
@@ -5,7 +5,7 @@
     <parent>\r
         <groupId>org.collectionspace.services</groupId>\r
         <artifactId>org.collectionspace.services.collectionobject</artifactId>\r
-        <version>3.2-SNAPSHOT</version>\r
+        <version>3.2.1-SNAPSHOT</version>\r
     </parent>\r
 \r
     <modelVersion>4.0.0</modelVersion>\r
index 55d6870869c131cd586f1885d56ed87f84754fd0..baae7d62c97afe3a79ee45feed9a252812d68b65 100644 (file)
         </tenant:serviceBindings>
         <!-- end account service meta-data -->
     
+        <!-- begin Article service meta-data -->
+        <tenant:serviceBindings id="Articles" name="Articles" type="procedure" version="0.1">
+            <!-- other URI paths through which this service could be accessed -->
+            <!--
+            <service:uriPath xmlns:service='http://collectionspace.org/services/config/service'>
+                /articles/*/authorityrefs/
+            </service:uriPath>
+            -->
+            <service:repositoryDomain xmlns:service="http://collectionspace.org/services/config/service">default-domain</service:repositoryDomain>
+            <service:documentHandler xmlns:service="http://collectionspace.org/services/config/service">org.collectionspace.services.article.nuxeo.ArticleDocumentModelHandler</service:documentHandler>
+            <service:DocHandlerParams xmlns:service="http://collectionspace.org/services/config/service">
+                <service:params>
+                    <service:ListResultsFields>
+                        <service:ListResultField>
+                            <service:element>articleNumber</service:element>
+                            <service:xpath>articleNumber</service:xpath>
+                        </service:ListResultField>
+                        <service:ListResultField>
+                            <service:element>articleContentUrl</service:element>
+                            <service:xpath>articleContentUrl</service:xpath>
+                        </service:ListResultField>
+                    </service:ListResultsFields>
+                </service:params>
+            </service:DocHandlerParams>
+            <service:validatorHandler xmlns:service="http://collectionspace.org/services/config/service">org.collectionspace.services.article.nuxeo.ArticleValidatorHandler</service:validatorHandler>
+            <service:properties xmlns:service="http://collectionspace.org/services/config/service">
+                <types:item xmlns:types="http://collectionspace.org/services/config/types">
+                    <types:key>objectNameProperty</types:key>
+                    <types:value>articleContentUrl</types:value>
+                </types:item>
+                <types:item xmlns:types="http://collectionspace.org/services/config/types">
+                    <types:key>objectNumberProperty</types:key>
+                    <types:value>articleNumber</types:value>
+                </types:item>
+            </service:properties>
+            <service:object xmlns:service="http://collectionspace.org/services/config/service" name="Article" version="0.1">
+                <service:part id="0" control_group="Managed" versionable="true" auditable="false" label="articles-system" updated="" order="0">
+                    <service:content contentType="application/xml">
+                        <service:xmlContent namespaceURI="http://collectionspace.org/services/config/system" schemaLocation="http://collectionspace.org/services/config/system http://collectionspace.org/services/config/system/system-response.xsd" />
+                    </service:content>
+                </service:part>
+                <service:part id="1" control_group="Managed" versionable="true" auditable="false" label="articles_common" updated="" order="1">
+                    <service:properties>
+                        <!-- Fields containing authority term references -->
+                        <!-- Fields containing term list / controlled vocabulary references -->
+                    </service:properties>
+                    <service:content contentType="application/xml">
+                        <service:xmlContent namespaceURI="http://collectionspace.org/services/article" schemaLocation="http://collectionspace.org/services/article http://services.collectionspace.org/article/articles_common.xsd" />
+                    </service:content>
+                </service:part>
+                <service:part id="2" control_group="Managed" versionable="true" auditable="false" label="collectionspace_core" updated="" order="2">
+                    <service:content contentType="application/xml">
+                        <service:xmlContent namespaceURI="http://collectionspace.org/collectionspace_core/" schemaLocation="http://collectionspace.org/collectionspace_core/ http://services.collectionspace.org/collectionspace_core.xsd" />
+                    </service:content>
+                </service:part>
+            </service:object>
+        </tenant:serviceBindings>
+        <!-- end Article service meta-data -->    
+    
         <!-- begin dimension service meta-data -->
         <tenant:serviceBindings id="Dimensions" name="Dimensions" type="utility" version="0.1">
             <!-- other URI paths through which this service could be accessed -->
index c85a1b8bb2fd4d0895d1cb0f698c21d7b7457a2c..c04368c1c934ded52b938a7012845939dff1c818 100644 (file)
@@ -46,7 +46,9 @@ import org.collectionspace.services.common.repository.RepositoryClientFactory;
 import org.collectionspace.services.common.security.UnauthorizedException;\r
 import org.collectionspace.services.common.storage.StorageClient;\r
 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;\r
-import org.jboss.resteasy.client.ClientResponse;\r
+import org.jboss.resteasy.core.ResourceMethod;\r
+import org.jboss.resteasy.spi.HttpRequest;\r
+\r
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
 \r
@@ -498,4 +500,10 @@ public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
         \r
         return result;\r
     }\r
+    \r
+       @Override\r
+       public boolean allowAnonymousAccess(HttpRequest request,\r
+                       ResourceMethod method) {\r
+               return false;\r
+       }    \r
 }\r
index 9b8b1451b2f6b222947eec2f715733940f3c6dc8..5e34217e1148d238bccd75f1e666e2eaa7ed0fa5 100644 (file)
@@ -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<IT, OT> {
      */
     public ServiceContextFactory<IT, OT> 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:
+                       <sec:filter-chain pattern="/articles/**"
+                              filters="none"/>
+     * See the "applicationContext-security.xml" file for details.
+     */
+       public boolean allowAnonymousAccess(HttpRequest request, ResourceMethod method);
+    
 }
index 300c0e3ad24c4fd0f3044a749c2cf6e4ee051c4f..2905214a7f8e013a5ac4bf539626948cb460da33 100644 (file)
@@ -123,9 +123,9 @@ public class AuthorizationCommon {
     public static final String DEFAULT_ADMIN_PASSWORD = "Administrator";\r
     public static final String DEFAULT_READER_PASSWORD = "reader";\r
 \r
-    public static String ROLE_SPRING_ADMIN_ID = "-1";\r
-    public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN";\r
-\r
+    public static final String ROLE_SPRING_ADMIN_ID = "-1";\r
+    public static final String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN";\r
+    \r
     // SQL for init tasks\r
        final private static String INSERT_ACCOUNT_ROLE_SQL_MYSQL = \r
                        "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)"\r
index 243e9ccd9661e5a343d56865ea61ff7f9739df54..ba9388a2cce1959b05f0437d2b5a420058abdb2c 100644 (file)
@@ -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<IT, OT>
      * 
      * @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;
index 0b8df0143172a206d3468ca3d9c3c83d5f249714..c13994bcad64d56ca25b5f20a5a34598c571abfb 100644 (file)
@@ -60,8 +60,10 @@ public class MultipartServiceContextFactory
      * @see org.collectionspace.services.common.context.ServiceContextFactory#createServiceContext(java.lang.String)
      */
     @Override
-    public ServiceContext<PoxPayloadIn, PoxPayloadOut> createServiceContext(String serviceName) throws Exception {
-        MultipartServiceContext ctx = new MultipartServiceContextImpl(serviceName);
+    public ServiceContext<PoxPayloadIn, PoxPayloadOut> 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<PoxPayloadIn, PoxPayloadOut> 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;
     }
         
index 7c786735c709afc1c00e78c3bd20d036add25c7e..3898cb85a8fa0b3fb5f727add056c991eaa89849 100644 (file)
@@ -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));
     }
 
index 93272ac8486d2a05647d3d4a468b993814261a64..2f23e54e6ab57aad68d30611cf5fb0608a00cc6c 100644 (file)
@@ -60,8 +60,8 @@ public class RemoteServiceContextFactory<IT, OT>
      * @see org.collectionspace.services.common.context.ServiceContextFactory#createServiceContext(java.lang.String)\r
      */\r
     @Override\r
-    public ServiceContext<IT, OT> createServiceContext(String serviceName) throws Exception {\r
-       RemoteServiceContext<IT, OT> ctx = new RemoteServiceContextImpl<IT, OT>(serviceName);\r
+    public ServiceContext<IT, OT> createServiceContext(String serviceName, UriInfo uriInfo) throws Exception {\r
+       RemoteServiceContext<IT, OT> ctx = new RemoteServiceContextImpl<IT, OT>(serviceName, uriInfo);\r
        return ctx;\r
     }\r
     \r
@@ -70,8 +70,8 @@ public class RemoteServiceContextFactory<IT, OT>
      */\r
     @Override\r
     public ServiceContext<IT, OT> createServiceContext(String serviceName,\r
-               IT theInput) throws Exception {\r
-       RemoteServiceContext<IT, OT> ctx = new RemoteServiceContextImpl<IT, OT>(serviceName, theInput);\r
+               IT theInput, UriInfo uriInfo) throws Exception {\r
+       RemoteServiceContext<IT, OT> ctx = new RemoteServiceContextImpl<IT, OT>(serviceName, theInput, uriInfo);\r
         return ctx;\r
     }\r
     \r
index 08c932432d6d367a2419df12eb724059fc22a699..b0cfee337ce10c7d5cb8e923f5d2160347f50e6e 100644 (file)
@@ -76,8 +76,8 @@ public class RemoteServiceContextImpl<IT, OT>
      * 
      * @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<IT, OT>
      * 
      * @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, OT>
                IT theInput,
                ResourceMap resourceMap,
                UriInfo uriInfo) throws UnauthorizedException {
-        this(serviceName, theInput);
+        this(serviceName, theInput, uriInfo);
         this.setResourceMap(resourceMap);
         this.setUriInfo(uriInfo);
         if (uriInfo != null) {
index bcc5e79a8ad3da81106ddfcc89100a681821404e..933426a5b1e8354e75c203a84d22147af1554737 100644 (file)
@@ -45,7 +45,7 @@ public interface ServiceContextFactory<IT, OT> {
      * 
      * @throws Exception the exception
      */
-    public ServiceContext<IT, OT> createServiceContext(String serviceName, IT input) throws Exception;
+    public ServiceContext<IT, OT> createServiceContext(String serviceName, IT input, UriInfo uriInfo) throws Exception;
     
     /**
      * Creates a new ServiceContext object.
@@ -56,7 +56,7 @@ public interface ServiceContextFactory<IT, OT> {
      * 
      * @throws Exception the exception
      */
-    public ServiceContext<IT, OT> createServiceContext(String serviceName) throws Exception;
+    public ServiceContext<IT, OT> createServiceContext(String serviceName, UriInfo uriInfo) throws Exception;
 
     /**
      * Creates a new ServiceContext object.
index f7de2c781f88e98773f878a73389833924c8faf9..ee1179482d1ca5eec0ae1a8bac9a2d5a3ac6333a 100644 (file)
  */
 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
index 0b8c1839301020bdae09e31dae28f5bfb647ff0f..49752e4858d48d52e5a0ea1940e672ea0662c6f7 100644 (file)
@@ -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 (file)
index 0000000..d272bc9
--- /dev/null
@@ -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);
+       }
+
+}
index 46795142e51e70b34b464145ea97a2e33575fec0..59966d278ee1a203f4b36e25acd30eba515f7f9d 100644 (file)
         <module>contact</module>
         <module>workflow</module>
         <module>media</module>
-        <module>JaxRsServiceProvider</module>
+        <module>article</module>        
         <!--module>sdk</module-->
         <module>IntegrationTests</module>
         <module>PerformanceTests</module>
         <module>security</module>
+        <module>JaxRsServiceProvider</module>
     </modules>
 
     <dependencies>