<artifactId>org.collectionspace.services.exit.service</artifactId>
<version>${project.version}</version>
</dependency>
-
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.restrictedmedia.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!--dependency>
<groupId>org.collectionspace.services</groupId>
import org.collectionspace.services.loanout.LoanoutResource;
import org.collectionspace.services.repatriationrequest.RepatriationRequestResource;
import org.collectionspace.services.nagprainventory.NagpraInventoryResource;
+import org.collectionspace.services.restrictedmedia.RestrictedMediaResource;
import org.collectionspace.services.summarydocumentation.SummaryDocumentationResource;
import org.collectionspace.services.transport.TransportResource;
import org.collectionspace.services.uoc.UocResource;
addResourceToMapAndSingletons(new ConsultationResource());
addResourceToMapAndSingletons(new DeaccessionResource());
addResourceToMapAndSingletons(new ExitResource());
+ addResourceToMapAndSingletons(new RestrictedMediaResource());
singletons.add(new IDResource());
SELECT csid
FROM id_generators
);
+
+-- RESTRICTED_MEDIA_NUMBER
+
+INSERT INTO id_generators
+ (csid, displayname, description, priority, last_generated_id, id_generator_state)
+ SELECT
+ '17772cbd-8de1-4969-ac2e-c51798bc4e75',
+ 'Restricted Media Number',
+ 'Identifies a restricted media document.',
+ '9',
+ '',
+'<org.collectionspace.services.id.SettableIDGenerator>
+ <parts>
+ <org.collectionspace.services.id.StringIDGeneratorPart>
+ <initialValue>RMR</initialValue>
+ <currentValue>RMR</currentValue>
+ </org.collectionspace.services.id.StringIDGeneratorPart>
+ <org.collectionspace.services.id.YearIDGeneratorPart>
+ <currentValue></currentValue>
+ </org.collectionspace.services.id.YearIDGeneratorPart>
+ <org.collectionspace.services.id.StringIDGeneratorPart>
+ <initialValue>.</initialValue>
+ <currentValue>.</currentValue>
+ </org.collectionspace.services.id.StringIDGeneratorPart>
+ <org.collectionspace.services.id.NumericIDGeneratorPart>
+ <maxLength>6</maxLength>
+ <initialValue>1</initialValue>
+ <currentValue>-1</currentValue>
+ </org.collectionspace.services.id.NumericIDGeneratorPart>
+ </parts>
+</org.collectionspace.services.id.SettableIDGenerator>'
+ WHERE '17772cbd-8de1-4969-ac2e-c51798bc4e75' NOT IN
+ (
+ SELECT csid
+ FROM id_generators
+ );
<module>nagprainventory</module>
<module>summarydocumentation</module>
<module>heldintrust</module>
+ <module>restrictedmedia</module>
<module>consultation</module>
<module>deaccession</module>
<module>IntegrationTests</module>
--- /dev/null
+<project name="restrictedmedia" default="package" basedir=".">
+ <description>
+ restrictedmedia service
+ </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="-V" />
+ <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" />
+ <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" />
+ <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" />
+ <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" />
+ <arg value="test" />
+ <arg value="${mvn.opts}" />
+ </exec>
+ </target>
+</project>
\ No newline at end of file
--- /dev/null
+<?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.restrictedmedia</artifactId>
+ <version>${revision}</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.collectionspace.services.restrictedmedia.client</artifactId>
+ <name>services.restrictedmedia.client</name>
+
+ <dependencies>
+ <!-- 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.blob.client</artifactId>
+ <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.restrictedmedia.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>
+ <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>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>collectionspace-services-restrictedmedia-client</finalName>
+ </build>
+</project>
\ No newline at end of file
--- /dev/null
+/*
+ * 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
+ *
+ * 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.core.Response;
+import org.collectionspace.services.restrictedmedia.RestrictedMediaCommon;
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
+
+/**
+ * RestrictedMediaClient.java
+ */
+public class RestrictedMediaClient
+ extends AbstractCommonListPoxServiceClientImpl<RestrictedMediaProxy, RestrictedMediaCommon> {
+
+ public static final String SERVICE_NAME = "restrictedmedia";
+ 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;
+
+ public RestrictedMediaClient() throws Exception {
+ super();
+ }
+
+ public RestrictedMediaClient(String clientPropertiesFilename) throws Exception {
+ super(clientPropertiesFilename);
+ }
+
+ @Override
+ public String getServicePathComponent() {
+ return SERVICE_PATH_COMPONENT;
+ }
+
+ @Override
+ public String getServiceName() {
+ return SERVICE_NAME;
+ }
+
+ @Override
+ public Class<RestrictedMediaProxy> getProxyClass() {
+ return RestrictedMediaProxy.class;
+ }
+
+ /**
+ * Creates a new blob resource from the form data and associates it with an existing media resource
+ *
+ * @param csid the media resource csid
+ * @param formDataOutput
+ * @return
+ */
+ public Response createBlobFromFormData(String csid, MultipartFormDataOutput formDataOutput) {
+ return getProxy().createBlobFromFormData(csid, formDataOutput);
+ }
+
+ /**
+ * Creates a new blob
+ *
+ * @param csid
+ * @return
+ */
+ public Response createBlobFromUri(String csid, String blobUri) {
+ // send the URI as both a query param and as content
+ return getProxy().createBlobFromUri(csid, blobUri, blobUri);
+ }
+
+ /*
+ * Create both a new media record
+ */
+ public Response createMediaAndBlobWithUri(PoxPayloadOut xmlPayload, String blobUri, boolean purgeOriginal) {
+ return getProxy().createMediaAndBlobWithUri(xmlPayload.getBytes(), blobUri, purgeOriginal);
+ }
+
+ /**
+ * @param csid
+ * @param xmlPayload
+ * @param URI
+ * @return
+ */
+ public Response update(String csid, PoxPayloadOut xmlPayload, String URI) {
+ return getProxy().update(csid, xmlPayload.getBytes());
+ }
+}
--- /dev/null
+/*
+ * 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
+ *
+ * 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.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
+
+/**
+ * RestrictedMediaProxy.java
+ */
+@Path(RestrictedMediaClient.SERVICE_PATH_PROXY)
+@Produces({"application/xml"})
+@Consumes({"application/xml"})
+public interface RestrictedMediaProxy extends CollectionSpaceCommonListPoxProxy {
+
+ @POST
+ @Path("{csid}")
+ @Consumes("multipart/form-data")
+ Response createBlobFromFormData(@PathParam("csid") String csid, MultipartFormDataOutput formDataOutput);
+
+ /**
+ *
+ * @param csid
+ * @param blobUri
+ * @param emptyXML param to force RESTEasy to produce a Content-Type header
+ * @return
+ */
+ @POST
+ @Path("{csid}")
+ @Produces("application/xml")
+ @Consumes("application/xml")
+ Response createBlobFromUri(
+ @PathParam("csid") String csid, @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri, String emptyXML);
+
+ @POST
+ @Produces("application/xml")
+ @Consumes("application/xml")
+ Response createMediaAndBlobWithUri(
+ byte[] xmlPayload,
+ @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri,
+ @QueryParam(BlobClient.BLOB_PURGE_ORIGINAL) boolean purgeOriginal);
+}
--- /dev/null
+/**
+ * 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:
+ * <p>
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+ * <p>
+ * Copyright © 2009 Regents of the University of California
+ * <p>
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ * <p>
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ * <p>
+ * 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 java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.ws.rs.core.Response;
+import org.collectionspace.services.PersonJAXBSchema;
+import org.collectionspace.services.client.CollectionSpaceClient;
+import org.collectionspace.services.client.PersonAuthorityClientUtils;
+import org.collectionspace.services.client.PersonClient;
+import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.RestrictedMediaClient;
+import org.collectionspace.services.jaxb.AbstractCommonList;
+import org.collectionspace.services.person.PersonTermGroup;
+import org.collectionspace.services.restrictedmedia.RestrictedMediaCommon;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+/**
+ * RestrictedMediaAuthRefsTest, carries out Authority References tests against a deployed and running
+ * Restricted Media Service.
+ */
+public class RestrictedMediaAuthRefsTest extends BaseServiceTest<AbstractCommonList> {
+ private final Logger logger = LoggerFactory.getLogger(RestrictedMediaAuthRefsTest.class);
+ final String PERSON_AUTHORITY_NAME = "MediaPersonAuth";
+ private String knownResourceId = null;
+ private List<String> mediaIdsCreated = new ArrayList<String>();
+ private List<String> personIdsCreated = new ArrayList<String>();
+ private String personAuthCSID = null;
+ private String publisherRefName = null;
+
+ @Override
+ public String getServicePathComponent() {
+ return RestrictedMediaClient.SERVICE_PATH_COMPONENT;
+ }
+
+ @Override
+ protected String getServiceName() {
+ return RestrictedMediaClient.SERVICE_NAME;
+ }
+
+ @Override
+ protected CollectionSpaceClient getClientInstance() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected CollectionSpaceClient getClientInstance(String clientPropertiesFilename) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected AbstractCommonList getCommonList(Response response) {
+ throw new UnsupportedOperationException();
+ }
+
+ private PoxPayloadOut createMediaInstance(String depositorRefName, String title) throws Exception {
+ RestrictedMediaCommon media = new RestrictedMediaCommon();
+ media.setIdentificationNumber(UUID.randomUUID().toString());
+ media.setTitle(title);
+ media.setPublisher(depositorRefName);
+
+ PoxPayloadOut multipart = new PoxPayloadOut(RestrictedMediaClient.SERVICE_PAYLOAD_NAME);
+ multipart.addPart(new RestrictedMediaClient().getCommonPartName(), media);
+ logger.debug("to be created, media common: {}", objectAsXmlString(media, RestrictedMediaCommon.class));
+ return multipart;
+ }
+
+ @Test(dataProvider = "testName")
+ public void createWithAuthRefs(String testName) throws Exception {
+ testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
+ String identifier = createIdentifier();
+
+ createPersonRefs();
+
+ // Create a new RestrictedMedia resource.
+ // One or more fields in this resource will be PersonAuthority references
+ // and will refer to Person resources by their refNames.
+ RestrictedMediaClient mediaClient = new RestrictedMediaClient();
+ PoxPayloadOut multipart = createMediaInstance(publisherRefName, "media.title-" + identifier);
+ Response res = mediaClient.create(multipart);
+ try {
+ assertStatusCode(res, testName);
+ // Store the ID returned from the first resource created for additional tests below.
+ if (knownResourceId == null) {
+ knownResourceId = extractId(res);
+ }
+ // Store the IDs from every resource created; delete on cleanup
+ mediaIdsCreated.add(extractId(res));
+ } finally {
+ if (res != null) {
+ res.close();
+ }
+ }
+ }
+
+ protected void createPersonRefs() throws Exception {
+ PersonClient personAuthClient = new PersonClient();
+ // Create a temporary PersonAuthority resource, and its corresponding refName by which it can be identified.
+ PoxPayloadOut multipart = PersonAuthorityClientUtils.createPersonAuthorityInstance(
+ PERSON_AUTHORITY_NAME, PERSON_AUTHORITY_NAME, personAuthClient.getCommonPartName());
+ Response res = personAuthClient.create(multipart);
+ assertStatusCode(res, "createPersonRefs (not a surefire test)");
+ personAuthCSID = extractId(res);
+
+ String authRefName = PersonAuthorityClientUtils.getAuthorityRefName(personAuthCSID, null);
+
+ String csid = createPerson("Owen the Cur", "Owner", "owenCurOwner", authRefName);
+ personIdsCreated.add(csid);
+ publisherRefName = PersonAuthorityClientUtils.getPersonRefName(personAuthCSID, csid, null);
+ }
+
+ protected String createPerson(String firstName, String surName, String shortId, String authRefName)
+ throws Exception {
+ PersonClient personAuthClient = new PersonClient();
+ Map<String, String> personInfo = new HashMap<String, String>();
+ personInfo.put(PersonJAXBSchema.FORE_NAME, firstName);
+ personInfo.put(PersonJAXBSchema.SUR_NAME, surName);
+ personInfo.put(PersonJAXBSchema.SHORT_IDENTIFIER, shortId + random.nextInt(1000));
+ List<PersonTermGroup> personTerms = new ArrayList<PersonTermGroup>();
+ PersonTermGroup term = new PersonTermGroup();
+ String termName = firstName + " " + surName;
+ term.setTermDisplayName(termName);
+ term.setTermName(termName);
+ personTerms.add(term);
+ PoxPayloadOut multipart = PersonAuthorityClientUtils.createPersonInstance(
+ personAuthCSID, authRefName, personInfo, personTerms, personAuthClient.getItemCommonPartName());
+ Response res = personAuthClient.createItem(personAuthCSID, multipart);
+ assertStatusCode(res, "createPerson (not a surefire test)");
+ return extractId(res);
+ }
+
+ /**
+ * Deletes all resources created by tests, after all tests have been run.
+ * <p/>
+ * This cleanup method will always be run, even if one or more tests fail.
+ * For this reason, it attempts to remove all resources created
+ * at any point during testing, even if some of those resources
+ * may be expected to be deleted by certain tests. Non-successful deletes are ignored and not reported
+ * @throws Exception
+ */
+ @AfterClass(alwaysRun = true)
+ public void cleanUp() throws Exception {
+ String noTestCleanup = System.getProperty("noTestCleanup");
+ if (Boolean.parseBoolean(noTestCleanup)) {
+ logger.debug("Skipping Cleanup phase...");
+ return;
+ }
+ logger.debug("Cleaning up temporary resources created for testing...");
+ PersonClient personAuthClient = new PersonClient();
+ // Delete Person resource(s) (before PersonAuthority resources).
+ for (String resourceId : personIdsCreated) {
+ // Note: Any non-success responses are ignored and not reported.
+ personAuthClient.deleteItem(personAuthCSID, resourceId);
+ }
+
+ if (personAuthCSID != null) {
+ personAuthClient.delete(personAuthCSID);
+ }
+
+ RestrictedMediaClient mediaClient = new RestrictedMediaClient();
+ for (String resourceId : mediaIdsCreated) {
+ mediaClient.delete(resourceId);
+ }
+ }
+}
--- /dev/null
+/**
+ * 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.io.File;
+import java.net.URL;
+import java.util.List;
+import java.util.UUID;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.collectionspace.services.client.CollectionSpaceClient;
+import org.collectionspace.services.client.PayloadOutputPart;
+import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.RestrictedMediaClient;
+import org.collectionspace.services.jaxb.AbstractCommonList;
+import org.collectionspace.services.restrictedmedia.LanguageList;
+import org.collectionspace.services.restrictedmedia.RestrictedMediaCommon;
+import org.collectionspace.services.restrictedmedia.SubjectList;
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * RestrictedMediaServiceTest, carries out tests against a deployed and running Restricted Media Service.
+ */
+public class RestrictedMediaServiceTest extends AbstractPoxServiceTestImpl<AbstractCommonList, RestrictedMediaCommon> {
+
+ private final Logger logger = LoggerFactory.getLogger(RestrictedMediaServiceTest.class);
+ private static final String PUBLIC_URL_DECK = "https://farm8.staticflickr.com/7231/6962564226_4bdfc17599_k_d.jpg";
+
+ private boolean mediaCleanup = true;
+
+ /**
+ * Sets up create tests.
+ */
+ @Override
+ protected void setupCreate() {
+ super.setupCreate();
+ String noMediaCleanup = System.getProperty(NO_MEDIA_CLEANUP);
+ if (Boolean.parseBoolean(noMediaCleanup)) {
+ // Don't delete the blobs that we created during the test cycle
+ this.mediaCleanup = false;
+ }
+ }
+
+ private boolean isMediaCleanup() {
+ return mediaCleanup;
+ }
+
+ @Override
+ public String getServicePathComponent() {
+ return RestrictedMediaClient.SERVICE_PATH_COMPONENT;
+ }
+
+ @Override
+ protected String getServiceName() {
+ return RestrictedMediaClient.SERVICE_NAME;
+ }
+
+ @Override
+ protected CollectionSpaceClient getClientInstance() throws Exception {
+ return new RestrictedMediaClient();
+ }
+
+ @Override
+ protected CollectionSpaceClient getClientInstance(String clientPropertiesFilename) throws Exception {
+ return new RestrictedMediaClient(clientPropertiesFilename);
+ }
+
+ @Override
+ protected AbstractCommonList getCommonList(Response response) {
+ return response.readEntity(AbstractCommonList.class);
+ }
+
+ /**
+ * Looks in the .../src/test/resources/blobs directory for files from which to create Blob
+ * instances.
+ *
+ * @param testName the test name
+ * @param fromUri - if 'true' then send the service a URI from which to create the blob.
+ * @param fromUri - if 'false' then send the service a multipart/form-data POST from which to create the blob.
+ * @throws Exception the exception
+ */
+ public void createBlob(String testName, boolean fromUri) throws Exception {
+ setupCreate();
+
+ // First create a restricted media record
+ RestrictedMediaClient client = new RestrictedMediaClient();
+ PoxPayloadOut multipart = createMediaInstance(createIdentifier());
+ Response mediaRes = client.create(multipart);
+ String mediaCsid = null;
+ try {
+ assertStatusCode(mediaRes, testName);
+ mediaCsid = extractId(mediaRes);
+ } finally {
+ if (mediaRes != null) {
+ mediaRes.close();
+ }
+ }
+
+ String currentDir = getResourceDir();
+ File blobsDir = new File(currentDir, BLOBS_DIR);
+ File blob = findBlobForMedia(blobsDir);
+ if (blob != null) {
+ createBlob(blob, fromUri, testName, mediaCsid);
+ } else {
+ logger.warn("Could not find blobbable file in {}", blobsDir);
+ }
+ }
+
+ /**
+ * Iterate a directory for a file which matches isBlobbable
+ *
+ * @param blobsDir the directory to iterate
+ * @return a blob or null
+ */
+ public File findBlobForMedia(File blobsDir) {
+ if (blobsDir.exists() && blobsDir.canRead()) {
+ File[] children = blobsDir.listFiles();
+ if (children != null && children.length > 0) {
+ // Since Media records can have only a single associated
+ // blob, we'll stop after we find a valid candidate.
+ for (File child : children) {
+ if (isBlobbable(child)) {
+ return child;
+ }
+ }
+ } else {
+ logger.warn("Directory: {} is empty or cannot be read.", blobsDir);
+ }
+ } else {
+ logger.warn("Directory: {} is missing or cannot be read.", blobsDir);
+ }
+
+ return null;
+ }
+
+ public void createBlob(File blobFile, boolean fromUri, String testName, String mediaCsid) throws Exception {
+ logger.debug("Processing file URI: {}", blobFile.getAbsolutePath());
+
+ String mimeType = getMimeType(blobFile);
+ logger.debug("MIME type is: {}", mimeType);
+
+ Response res;
+ RestrictedMediaClient client = new RestrictedMediaClient();
+ if (fromUri) {
+ URL childUrl = blobFile.toURI().toURL();
+ res = client.createBlobFromUri(mediaCsid, childUrl.toString());
+ } else {
+ MultipartFormDataOutput formData = new MultipartFormDataOutput();
+ formData.addFormData("file", blobFile, MediaType.valueOf(mimeType));
+ res = client.createBlobFromFormData(mediaCsid, formData);
+ }
+
+ try {
+ assertStatusCode(res, testName);
+ String blobCsid = extractId(res);
+ if (isMediaCleanup()) {
+ allResourceIdsCreated.add(blobCsid);
+ allResourceIdsCreated.add(mediaCsid);
+ }
+ } finally {
+ if (res != null) {
+ res.close();
+ }
+ }
+ }
+
+ @Test(dataProvider = "testName", dependsOnMethods = {"CRUDTests"})
+ public void createWithBlobUri(String testName) throws Exception {
+ createBlob(testName, true /*with URI*/);
+ }
+
+ @Test(dataProvider = "testName", dependsOnMethods = {"createWithBlobUri"})
+ public void createMediaAndBlobWithUri(String testName) throws Exception {
+ RestrictedMediaClient client = new RestrictedMediaClient();
+ PoxPayloadOut multipart = createMediaInstance(createIdentifier());
+
+ // purge the original
+ Response mediaRes = client.createMediaAndBlobWithUri(multipart, PUBLIC_URL_DECK, true);
+ String mediaCsid = null;
+ try {
+ assertStatusCode(mediaRes, testName);
+ mediaCsid = extractId(mediaRes);
+ if (isMediaCleanup()) {
+ allResourceIdsCreated.add(mediaCsid);
+ }
+ } finally {
+ if (mediaRes != null) {
+ mediaRes.close();
+ }
+ }
+ }
+
+ @Test(dataProvider = "testName", dependsOnMethods = {"createWithBlobUri"})
+ public void createWithBlobPost(String testName) throws Exception {
+ createBlob(testName, false /*with POST*/);
+ }
+
+ // ---------------------------------------------------------------
+ // Utility tests : tests of code used in tests above
+ // ---------------------------------------------------------------
+
+ @Override
+ protected PoxPayloadOut createInstance(String identifier) throws Exception {
+ return createMediaInstance(identifier);
+ }
+
+ // ---------------------------------------------------------------
+ // Utility methods used by tests above
+ // ---------------------------------------------------------------
+ private PoxPayloadOut createMediaInstance(String title) throws Exception {
+ String identifier = "media.title-" + title;
+ RestrictedMediaCommon media = new RestrictedMediaCommon();
+ media.setTitle(identifier);
+ media.setIdentificationNumber(UUID.randomUUID().toString());
+ media.setContributor("Joe-bob briggs");
+ media.setCoverage("Lots of stuff");
+ media.setPublisher("Ludicrum Enterprises");
+ SubjectList subjects = new SubjectList();
+ List<String> subjList = subjects.getSubject();
+ subjList.add("Pints of blood");
+ subjList.add("Much skin");
+ media.setSubjectList(subjects);
+ LanguageList languages = new LanguageList();
+ List<String> langList = languages.getLanguage();
+ langList.add("English");
+ langList.add("German");
+ media.setLanguageList(languages);
+ PoxPayloadOut multipart = new PoxPayloadOut(RestrictedMediaClient.SERVICE_PAYLOAD_NAME);
+ PayloadOutputPart commonPart = multipart.addPart(media, MediaType.APPLICATION_XML_TYPE);
+ commonPart.setLabel(new RestrictedMediaClient().getCommonPartName());
+
+ logger.debug("to be created, media common");
+ logger.debug(objectAsXmlString(media, RestrictedMediaCommon.class));
+
+ return multipart;
+ }
+
+ @Override
+ protected PoxPayloadOut createInstance(String commonPartName, String identifier) throws Exception {
+ return createMediaInstance(identifier);
+ }
+
+ @Override
+ protected RestrictedMediaCommon updateInstance(final RestrictedMediaCommon original) {
+ RestrictedMediaCommon result = new RestrictedMediaCommon();
+ result.setTitle("updated-" + original.getTitle());
+ return result;
+ }
+
+ @Override
+ protected void compareUpdatedInstances(RestrictedMediaCommon original, RestrictedMediaCommon updated) {
+ Assert.assertEquals(updated.getTitle(), original.getTitle());
+ }
+
+ @Override
+ @Test(dataProvider = "testName",
+ dependsOnMethods = {"org.collectionspace.services.client.test.AbstractServiceTestImpl.baseCRUDTests"})
+ public void CRUDTests(String testName) {}
+}
--- /dev/null
+<?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.restrictedmedia</artifactId>
+ <groupId>org.collectionspace.services</groupId>
+ <version>${revision}</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.collectionspace.services.restrictedmedia.jaxb</artifactId>
+ <name>services.restrictedmedia.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-restrictedmedia-jaxb</finalName>
+ <defaultGoal>install</defaultGoal>
+ <plugins>
+ <plugin>
+ <groupId>org.jvnet.jaxb2.maven2</groupId>
+ <artifactId>maven-jaxb2-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+
+<!--
+ RestrictedMedia schema (XSD)
+
+ Entity : RestrictedMedia
+ Part : Common
+ Used for: JAXB binding between XML and Java objects
+-->
+<xs:schema
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+ jaxb:version="2.0"
+ xmlns="http://collectionspace.org/services/restrictedmedia"
+ targetNamespace="http://collectionspace.org/services/restrictedmedia"
+ version="0.1"
+>
+ <!-- RestrictedMedia Information Group -->
+ <xs:element name="restrictedmedia_common">
+ <xs:annotation>
+ <xs:appinfo>
+ <jaxb:class name="RestrictedMediaCommon" />
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:complexType>
+ <xs:sequence>
+ <!-- Media Information Group -->
+ <xs:element name="contributor" type="xs:string"/>
+ <xs:element name="copyrightStatement" type="xs:string"/>
+ <xs:element name="coverage" type="xs:string"/>
+ <xs:element name="creator" type="xs:string"/>
+ <xs:element name="dateGroupList" type="dateGroupList"/>
+ <xs:element name="dateCreated" type="xs:string"/>
+ <xs:element name="dateModified" type="xs:string"/>
+ <xs:element name="description" type="xs:string"/>
+ <xs:element name="measuredPartGroupList" type="measuredPartGroupList"/>
+ <xs:element name="filename" type="xs:string"/>
+ <xs:element name="format" type="xs:string"/>
+ <xs:element name="identificationNumber" type="xs:string"/>
+ <xs:element name="languageList" type="languageList"/>
+ <xs:element name="location" type="xs:string"/>
+ <xs:element name="publisher" type="xs:string"/>
+ <xs:element name="relationList" type="relationList"/>
+ <xs:element name="rightsHolder" type="xs:string"/>
+ <xs:element name="source" type="xs:string"/>
+ <xs:element name="sourceUrl" type="xs:string"/>
+ <xs:element name="subjectList" type="subjectList"/>
+ <xs:element name="title" type="xs:string"/>
+ <xs:element name="typeList" type="typeList"/>
+ <xs:element name="uri" type="xs:string" />
+ <xs:element name="blobCsid" type="xs:string" />
+ <xs:element name="externalUrl" type="xs:string" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:complexType name="dateGroupList">
+ <xs:sequence>
+ <xs:element name="dateGroup" type="dateGroup" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="dateGroup">
+ <xs:sequence>
+ <xs:element name="dateDisplayDate" type="xs:string"/>
+ <xs:element name="dateAssociation" type="xs:string"/>
+ <xs:element name="dateEarliestSingleYear" type="xs:integer"/>
+ <xs:element name="dateEarliestSingleMonth" type="xs:integer"/>
+ <xs:element name="dateEarliestSingleDay" type="xs:integer"/>
+ <xs:element name="dateEarliestSingleEra" type="xs:string"/>
+ <xs:element name="dateEarliestSingleCertainty" type="xs:string"/>
+ <xs:element name="dateEarliestSingleQualifier" type="xs:string"/>
+ <xs:element name="dateEarliestSingleQualifierValue" type="xs:integer"/>
+ <xs:element name="dateEarliestSingleQualifierUnit" type="xs:string"/>
+ <xs:element name="dateLatestYear" type="xs:integer"/>
+ <xs:element name="dateLatestMonth" type="xs:integer"/>
+ <xs:element name="dateLatestDay" type="xs:integer"/>
+ <xs:element name="dateLatestEra" type="xs:string"/>
+ <xs:element name="dateLatestCertainty" type="xs:string"/>
+ <xs:element name="dateLatestQualifier" type="xs:string"/>
+ <xs:element name="dateLatestQualifierValue" type="xs:integer"/>
+ <xs:element name="dateLatestQualifierUnit" type="xs:string"/>
+ <xs:element name="datePeriod" type="xs:string"/>
+ <xs:element name="dateNote" type="xs:string"/>
+ <xs:element name="dateEarliestScalarValue" type="xs:date"/>
+ <xs:element name="dateLatestScalarValue" type="xs:date"/>
+ <xs:element name="scalarValuesComputed" type="xs:boolean"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="dateList">
+ <xs:sequence>
+ <xs:element name="date" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="measuredPartGroupList">
+ <xs:sequence>
+ <xs:element name="measuredPartGroup" type="measuredPartGroup" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="measuredPartGroup">
+ <xs:sequence>
+ <xs:element name="measuredPart" type="xs:string"/>
+ <xs:element name="dimensionSummary" type="xs:string"/>
+ <xs:element name="dimensionSubGroupList" type="dimensionSubGroupList"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="dimensionSubGroupList">
+ <xs:sequence>
+ <xs:element name="dimensionSubGroup" type="dimensionSubGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="dimensionSubGroup">
+ <xs:sequence>
+ <xs:element name="dimension" type="xs:string"/>
+ <xs:element name="measuredBy" type="xs:string"/>
+ <xs:element name="measurementUnit" type="xs:string"/>
+ <xs:element name="measurementMethod" type="xs:string"/>
+ <xs:element name="value" type="xs:decimal"/>
+ <xs:element name="valueDate" type="xs:string"/>
+ <xs:element name="valueQualifier" type="xs:string"/>
+ <xs:element name="dimensionNote" type="xs:string"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="languageList">
+ <xs:sequence>
+ <xs:element name="language" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="relationList">
+ <xs:sequence>
+ <xs:element name="relation" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="subjectList">
+ <xs:sequence>
+ <xs:element name="subject" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="typeList">
+ <xs:sequence>
+ <xs:element name="type" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
--- /dev/null
+<?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.main</artifactId>
+ <version>${revision}</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.collectionspace.services.restrictedmedia</artifactId>
+ <name>services.restrictedmedia</name>
+ <packaging>pom</packaging>
+
+ <properties>
+ <!-- spotless 2.30.0 is the last version that supports java 8 -->
+ <spotless.version>2.30.0</spotless.version>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.diffplug.spotless</groupId>
+ <artifactId>spotless-maven-plugin</artifactId>
+ <version>${spotless.version}</version>
+ <configuration>
+ <formats>
+ <!-- you can define as many formats as you want, each is independent -->
+ <format>
+ <includes>
+ <include>src/main/java/**/*.java</include>
+ <include>src/test/java/**/*.java</include>
+ </includes>
+ <trimTrailingWhitespace />
+ <endWithNewline />
+ <indent>
+ <spaces>true</spaces>
+ <spacesPerTab>4</spacesPerTab>
+ </indent>
+ </format>
+ </formats>
+ <!-- define a language-specific format -->
+ <java>
+ <palantirJavaFormat />
+ </java>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <modules>
+ <module>jaxb</module>
+ <module>service</module>
+ <module>client</module>
+ </modules>
+
+</project>
\ No newline at end of file
--- /dev/null
+<?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.restrictedmedia</artifactId>
+ <version>${revision}</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.collectionspace.services.restrictedmedia.service</artifactId>
+ <name>services.restrictedmedia.service</name>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.blob.client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.blob.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.media.jaxb</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.restrictedmedia.jaxb</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.restrictedmedia.client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- External dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- javax -->
+ <dependency>
+ <groupId>javax.security</groupId>
+ <artifactId>jaas</artifactId>
+ <version>1.0.01</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>
+ <dependency>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>tomcat-servlet-api</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>collectionspace-services-restrictedmedia</finalName>
+ </build>
+</project>
--- /dev/null
+/*
+ * 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
+ *
+ * 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.restrictedmedia;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.collectionspace.services.blob.BlobResource;
+import org.collectionspace.services.client.BlobClient;
+import org.collectionspace.services.client.CollectionSpaceClientUtils;
+import org.collectionspace.services.client.PayloadOutputPart;
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.RestrictedMediaClient;
+import org.collectionspace.services.common.NuxeoBasedResource;
+import org.collectionspace.services.common.ResourceMap;
+import org.collectionspace.services.common.ServiceMessages;
+import org.collectionspace.services.common.UriInfoWrapper;
+import org.collectionspace.services.common.blob.BlobInput;
+import org.collectionspace.services.common.blob.BlobUtil;
+import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.nuxeo.client.java.CommonList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Path(RestrictedMediaClient.SERVICE_PATH)
+@Consumes("application/xml")
+@Produces("application/xml")
+public class RestrictedMediaResource extends NuxeoBasedResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(RestrictedMediaResource.class);
+
+ static final RestrictedMediaClient mediaClient = createMediaClient();
+
+ @Override
+ protected String getVersionString() {
+ return "$LastChangedRevision$";
+ }
+
+ @Override
+ public String getServiceName() {
+ return RestrictedMediaClient.SERVICE_NAME;
+ }
+
+ @Override
+ public Class<RestrictedMediaCommon> getCommonPartClass() {
+ return RestrictedMediaCommon.class;
+ }
+
+ public String getCommonPartName() {
+ return mediaClient.getCommonPartName();
+ }
+
+ private static RestrictedMediaClient createMediaClient() {
+ RestrictedMediaClient result;
+
+ try {
+ result = new RestrictedMediaClient();
+ } catch (Exception e) {
+ String errMsg = "Could not create a new restricted media client for the RestrictedMedia resource.";
+ logger.error(errMsg, e);
+ throw new RuntimeException();
+ }
+
+ return result;
+ }
+
+ private String getBlobCsid(String mediaCsid) throws Exception {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> mediaContext = createServiceContext();
+
+ BlobInput blobInput = BlobUtil.getBlobInput(mediaContext);
+ blobInput.setSchemaRequested(true);
+
+ // set the blobInput blobCsid
+ get(mediaCsid, mediaContext);
+
+ String result = blobInput.getBlobCsid();
+
+ ensureCSID(result, READ);
+
+ return result;
+ }
+
+ /*
+ * Creates a new media record/resource AND creates a new blob (using a URL pointing to a media file/resource) and
+ * associates it with the new media record/resource.
+ */
+ protected Response createBlobWithUri(UriInfo uriInfo, String blobUri) {
+ Response response;
+
+ try {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(BlobClient.SERVICE_NAME, uriInfo);
+ BlobInput blobInput = BlobUtil.getBlobInput(ctx);
+ blobInput.createBlobFile(blobUri);
+
+ // By now the binary bits have been created, and we just need to create the metadata blob
+ // record -this info is in the blobInput var
+ response = create(null, ctx);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
+ }
+
+ return response;
+ }
+
+ /*
+ * Looks for a blobUri query param from a POST. If it finds one then it creates a blob AND a media resource and
+ * associates them.
+ *
+ * @see org.collectionspace.services.common.ResourceBase#create(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.ResourceMap, javax.ws.rs.core.UriInfo, java.lang.String)
+ */
+ @Override
+ public Response create(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
+ @Context ResourceMap resourceMap,
+ @Context UriInfo uriInfo,
+ String xmlPayload) {
+ uriInfo = new UriInfoWrapper(uriInfo);
+
+ // create a blob resource/record first and then the media resource/record
+ MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
+ String blobUri = queryParams.getFirst(BlobClient.BLOB_URI_PARAM);
+ if (blobUri != null && !blobUri.isEmpty()) {
+ // uses the blob resource and doc handler to create the blob
+ Response result = createBlobWithUri(uriInfo, blobUri);
+ String blobCsid = CollectionSpaceClientUtils.extractId(result);
+
+ // Add the new blob's csid as an artificial query param -the media doc handler will look for this
+ queryParams.add(BlobClient.BLOB_CSID_PARAM, blobCsid);
+ }
+
+ return super.create(parentCtx, resourceMap, uriInfo, xmlPayload);
+ }
+
+ @Override
+ public byte[] update(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
+ @Context ResourceMap resourceMap,
+ @Context UriInfo uriInfo,
+ @PathParam("csid") String csid,
+ String xmlPayload) {
+ uriInfo = new UriInfoWrapper(uriInfo);
+ // If we find a "blobUri" query param, then we need to create a blob resource/record first and then the media
+ // resource/record
+ MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
+ String blobUri = queryParams.getFirst(BlobClient.BLOB_URI_PARAM);
+ if (blobUri != null && !blobUri.isEmpty()) {
+ // uses the blob resource and doc handler to create the blob
+ Response blobResponse = createBlobWithUri(uriInfo, blobUri);
+ String blobCsid = CollectionSpaceClientUtils.extractId(blobResponse);
+ // Add the new blob's csid as an artificial query param -the media doc handler will look
+ queryParams.add(BlobClient.BLOB_CSID_PARAM, blobCsid);
+ }
+
+ // finish the media resource PUT request
+ return super.update(parentCtx, resourceMap, uriInfo, csid, xmlPayload);
+ }
+
+ /*
+ * Creates a new blob (using a URL pointing to a media file/resource) and associate it with
+ * an existing media record/resource.
+ */
+ @POST
+ @Path("{csid}")
+ @Consumes("application/xml")
+ @Produces("application/xml")
+ public Response createBlobWithUriAndUpdateMedia(@PathParam("csid") String csid,
+ @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri) {
+ Response response;
+
+ try {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(BlobClient.SERVICE_NAME);
+ BlobInput blobInput = BlobUtil.getBlobInput(ctx);
+ blobInput.createBlobFile(blobUri);
+ response = create(null, ctx);
+
+ // Next, update the RestrictedMedia record to be linked to the blob
+ // and put the blobInput into the RestrictedMedia context
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> mediaContext = createServiceContext();
+ BlobUtil.setBlobInput(mediaContext, blobInput);
+ update(csid, null, mediaContext);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
+ }
+
+ return response;
+ }
+
+ @PUT
+ @Path("{csid}/blob")
+ @Consumes("multipart/form-data")
+ @Produces("application/xml")
+ public Response updateMediaByCreatingBlob(
+ @Context HttpServletRequest req,
+ @PathParam("csid") String csid,
+ @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri) {
+ return createBlob(req, csid, blobUri);
+ }
+
+ /*
+ * Creates a new blob (using the incoming multipart form data) and associates it with an existing media
+ * record/resource. If a URL query param is passed in as well, we use the URL to create the new blob instead of
+ * the multipart form data.
+ *
+ * todo: Why is this deprecated?
+ */
+ @POST
+ @Path("{csid}")
+ @Consumes("multipart/form-data")
+ @Produces("application/xml")
+ @Deprecated
+ public Response createBlob(
+ @Context HttpServletRequest req,
+ @PathParam("csid") String csid,
+ @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri) {
+ Response response;
+ try {
+ if (blobUri == null) {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> blobContext =
+ createServiceContext(BlobClient.SERVICE_NAME, (PoxPayloadIn) null);
+ BlobInput blobInput = BlobUtil.getBlobInput(blobContext);
+ blobInput.createBlobFile(req, null);
+ response = create(null, blobContext);
+
+ // Next, update the Media record to be linked to the blob and put the blobInput into the Media context
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> mediaContext = createServiceContext();
+ BlobUtil.setBlobInput(mediaContext, blobInput);
+ update(csid, null, mediaContext);
+ } else {
+ // A URI query param overrides the incoming multipart/form-data payload in the request
+ response = createBlobWithUriAndUpdateMedia(csid, blobUri);
+ }
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
+ }
+
+ return response;
+ }
+
+ @GET
+ @Path("{csid}/blob")
+ public byte[] getBlobInfo(@PathParam("csid") String csid) {
+ PoxPayloadOut result;
+
+ try {
+ String blobCsid = getBlobCsid(csid);
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> blobContext = createServiceContext(BlobClient.SERVICE_NAME);
+ result = get(blobCsid, blobContext);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
+ }
+
+ return result.getBytes();
+ }
+
+ @GET
+ @Path("{csid}/blob/content")
+ public Response getBlobContent(
+ @PathParam("csid") String csid, @Context Request requestInfo, @Context UriInfo uriInfo) {
+ Response result;
+ BlobResource blobResource = new BlobResource();
+
+ try {
+ ensureCSID(csid, READ);
+ String blobCsid = getBlobCsid(csid);
+ result = blobResource.getBlobContent(blobCsid, requestInfo, uriInfo);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
+ }
+
+ return result;
+ }
+
+ @GET
+ @Path("{csid}/blob/derivatives/{derivativeTerm}/content")
+ public Response getDerivativeContent(
+ @PathParam("csid") String csid,
+ @PathParam("derivativeTerm") String derivativeTerm,
+ @Context Request requestInfo,
+ @Context UriInfo uriInfo) {
+ Response result;
+ BlobResource blobResource = new BlobResource();
+
+ try {
+ ensureCSID(csid, READ);
+ String blobCsid = getBlobCsid(csid);
+ result = blobResource.getDerivativeContent(blobCsid, derivativeTerm, requestInfo, uriInfo);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
+ }
+
+ return result;
+ }
+
+ @GET
+ @Path("{csid}/blob/derivatives/{derivativeTerm}")
+ public byte[] getDerivative(@PathParam("csid") String csid, @PathParam("derivativeTerm") String derivativeTerm) {
+ PoxPayloadOut result;
+ BlobResource blobResource = new BlobResource();
+
+ try {
+ ensureCSID(csid, READ);
+ String blobCsid = getBlobCsid(csid);
+ String xmlPayload = blobResource.getDerivative(blobCsid, derivativeTerm);
+ result = new PoxPayloadOut(xmlPayload.getBytes());
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
+ }
+
+ return result.getBytes();
+ }
+
+ @GET
+ @Path("{csid}/blob/derivatives")
+ @Produces("application/xml")
+ public CommonList getDerivatives(@PathParam("csid") String csid) {
+ CommonList result = null;
+ BlobResource blobResource = new BlobResource();
+
+ try {
+ ensureCSID(csid, READ);
+ String blobCsid = getBlobCsid(csid);
+ result = blobResource.getDerivatives(blobCsid);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
+ }
+
+ return result;
+ }
+
+ @DELETE
+ @Path("{csid}")
+ @Override
+ public Response delete(@PathParam("csid") String csid) {
+ BlobResource blob = new BlobResource();
+
+ try {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
+ PoxPayloadOut mediaPayload = get(csid, ctx);
+ PayloadOutputPart mediaPayloadPart = mediaPayload.getPart(getCommonPartName());
+ RestrictedMediaCommon mediaCommon = (RestrictedMediaCommon) mediaPayloadPart.getBody();
+ String blobCsid = mediaCommon.getBlobCsid();
+
+ // Delete the blob if it exists.
+ if (blobCsid != null && !blobCsid.isEmpty()) {
+ Response response = blob.delete(blobCsid);
+ if (response.getStatus() != Response.Status.OK.getStatusCode()) {
+ logger.debug("Problem deleting related blob record of RestrictedMedia record: " +
+ "RestrictedMedia CSID={} Blob CSID={}", csid, blobCsid);
+ }
+ }
+
+ return super.delete(ctx, csid);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ *
+ * 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.restrictedmedia.nuxeo;
+
+import javax.ws.rs.core.MultivaluedMap;
+import org.collectionspace.services.MediaJAXBSchema;
+import org.collectionspace.services.client.BlobClient;
+import org.collectionspace.services.common.blob.BlobInput;
+import org.collectionspace.services.common.blob.BlobUtil;
+import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.common.document.DocumentWrapper;
+import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
+import org.collectionspace.services.restrictedmedia.RestrictedMediaCommon;
+import org.nuxeo.ecm.core.api.DocumentModel;
+
+/**
+ * RestrictedMediaDocumentModelHandler
+ */
+public class RestrictedMediaDocumentModelHandler extends NuxeoDocumentModelHandler<RestrictedMediaCommon> {
+
+ private RestrictedMediaCommon getCommonPartProperties(DocumentModel docModel) {
+ String label = getServiceContext().getCommonPartLabel();
+ RestrictedMediaCommon result = new RestrictedMediaCommon();
+
+ result.setBlobCsid((String) docModel.getProperty(label, MediaJAXBSchema.blobCsid));
+ return result;
+ }
+
+ @Override
+ public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
+ ServiceContext ctx = getServiceContext();
+
+ final BlobInput blobInput = BlobUtil.getBlobInput(ctx);
+ if (blobInput.isSchemaRequested()) {
+ DocumentModel docModel = wrapDoc.getWrappedObject();
+ RestrictedMediaCommon mediaCommon = getCommonPartProperties(docModel);
+ String blobCsid = mediaCommon.getBlobCsid();
+ blobInput.setBlobCsid(blobCsid);
+ } else {
+ super.extractAllParts(wrapDoc);
+ }
+ }
+
+ @Override
+ public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
+ String blobCsid;
+ ServiceContext ctx = getServiceContext();
+
+ BlobInput blobInput = BlobUtil.getBlobInput(ctx);
+ if (blobInput.getBlobCsid() != null) {
+ blobCsid = blobInput.getBlobCsid();
+ } else {
+ MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
+ blobCsid = queryParams.getFirst(BlobClient.BLOB_CSID_PARAM);
+ // we're creating a blob from a URI and creating a new media resource as well
+ // extract all the other fields from the input payload
+ super.fillAllParts(wrapDoc, action);
+ }
+
+ if (blobCsid != null) {
+ DocumentModel documentModel = wrapDoc.getWrappedObject();
+ documentModel.setProperty(ctx.getCommonPartLabel(), MediaJAXBSchema.blobCsid, blobCsid);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ *
+ * 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.restrictedmedia.nuxeo;
+
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.common.document.InvalidDocumentException;
+import org.collectionspace.services.common.document.ValidatorHandlerImpl;
+import org.collectionspace.services.restrictedmedia.RestrictedMediaCommon;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ValidatorHandler for RestrictedMedia
+ *
+ * Checks for presence of restrictedmedia_common and restrictedmedia_common/identificationNumber
+ */
+public class RestrictedMediaValidatorHandler extends ValidatorHandlerImpl<PoxPayloadIn, PoxPayloadOut> {
+ private final Logger logger = LoggerFactory.getLogger(RestrictedMediaValidatorHandler.class);
+
+ private static final String COMMON_PART_MISSING =
+ "Validation exception: restrictedmedia_common part is missing";
+ private static final String IDENTIFICATION_NUMBER_MISSING =
+ "Validation exception: The restricted media field \"identificationNumber\" cannot be empty or missing";
+
+ @Override
+ protected Class<?> getCommonPartClass() {
+ return RestrictedMediaCommon.class;
+ }
+
+ @Override
+ protected void handleCreate() throws InvalidDocumentException {
+ final RestrictedMediaCommon restrictedMedia = (RestrictedMediaCommon) getCommonPart();
+ if (restrictedMedia == null) {
+ logger.error(COMMON_PART_MISSING);
+ throw new InvalidDocumentException(COMMON_PART_MISSING);
+ }
+
+ final String identificationNumber = restrictedMedia.getIdentificationNumber();
+ if (identificationNumber == null || identificationNumber.isEmpty()) {
+ logger.error(IDENTIFICATION_NUMBER_MISSING);
+ throw new InvalidDocumentException(IDENTIFICATION_NUMBER_MISSING);
+ }
+ }
+
+ @Override
+ protected void handleGet() {}
+
+ @Override
+ protected void handleGetAll() {}
+
+ @Override
+ protected void handleUpdate() {}
+
+ @Override
+ protected void handleDelete() {}
+}