Skip to content

Commit

Permalink
Add an exception and 400 response code when making datastream-specifi…
Browse files Browse the repository at this point in the history
…c requests on non-datastream resources.

Resolves: https://www.pivotaltracker.com/story/show/75915350
  • Loading branch information
mikedurbin authored and Andrew Woods committed Aug 7, 2014
1 parent 3845a80 commit 2e16f82
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 39 deletions.
Expand Up @@ -193,7 +193,7 @@ public void testGetFederatedObject() throws RepositoryException {
public void testGetFederatedContent() throws RepositoryException {
final Session session = repo.login();

final Node node = datastreamService.getDatastreamNode(session, testFilePath() + "/jcr:content");
final Node node = nodeService.getObject(session, testFilePath() + "/jcr:content").getNode();
assertNotNull(node);

final NodeType[] mixins = node.getMixinNodeTypes();
Expand Down Expand Up @@ -221,7 +221,7 @@ public void testGetFederatedContent() throws RepositoryException {
public void testFixity() throws RepositoryException, IOException, NoSuchAlgorithmException {
final Session session = repo.login();

checkFixity(datastreamService.getDatastreamNode(session, testFilePath() + "/jcr:content"));
checkFixity(nodeService.getObject(session, testFilePath() + "/jcr:content").getNode());

session.save();
session.logout();
Expand All @@ -231,7 +231,7 @@ public void testFixity() throws RepositoryException, IOException, NoSuchAlgorith
public void testChangedFileFixity() throws RepositoryException, IOException, NoSuchAlgorithmException {
final Session session = repo.login();

final Node node = datastreamService.getDatastreamNode(session, testFilePath() + "/jcr:content");
final Node node = nodeService.getObject(session, testFilePath() + "/jcr:content").getNode();

final String originalFixity = checkFixity(node);

Expand Down
Expand Up @@ -135,6 +135,19 @@ public void testPutDatastream() throws Exception {
assertNotEquals("Last-Modified should not be blank for new nodes", lastmod.trim(), "");
}

@Test
public void testPutDatastreamContentOnObject() throws Exception {
final String content = "foo";
final String pid = getRandomUniquePid();
createObject(pid);

final HttpPut put = new HttpPut(serverAddress + pid + "/fcr:content");
put.setEntity(new StringEntity(content));
final HttpResponse response = client.execute(put);
assertEquals("Expected 400 response code when PUTing content on an object (as opposed to a datastream).",
400, response.getStatusLine().getStatusCode());
}

@Test
public void testPutDatastreamWithContentDisposition() throws Exception {
final String pid = getRandomUniquePid();
Expand Down
Expand Up @@ -27,6 +27,7 @@
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import org.fcrepo.kernel.exception.ResourceTypeException;
import org.slf4j.Logger;

/**
Expand All @@ -46,8 +47,9 @@ public class RepositoryExceptionMapper implements
public Response toResponse(final RepositoryException e) {

LOGGER.warn("Caught repository exception: {}", e.getMessage() );

if ( e.getMessage().matches("Error converting \".+\" from String to a Name")) {
if (e instanceof ResourceTypeException) {
return status(BAD_REQUEST).entity(null).build();
} else if ( e.getMessage().matches("Error converting \".+\" from String to a Name")) {
return status(BAD_REQUEST).entity(e.getMessage()).build();
} else if ( e instanceof ValueFormatException ) {
return status(BAD_REQUEST).entity(e.getMessage()).build();
Expand Down
Expand Up @@ -18,6 +18,7 @@
import static com.codahale.metrics.MetricRegistry.name;
import static org.fcrepo.kernel.impl.services.ServiceHelpers.getNodePropertySize;
import static org.fcrepo.kernel.impl.utils.FedoraTypesUtils.isFedoraDatastream;
import static org.fcrepo.kernel.impl.utils.FedoraTypesUtils.isFrozen;
import static org.fcrepo.metrics.RegistryService.getMetrics;
import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;
Expand All @@ -37,6 +38,7 @@
import org.fcrepo.kernel.Datastream;
import org.fcrepo.kernel.FedoraObject;
import org.fcrepo.kernel.exception.InvalidChecksumException;
import org.fcrepo.kernel.exception.ResourceTypeException;
import org.fcrepo.kernel.services.policy.StoragePolicyDecisionPoint;
import org.fcrepo.kernel.utils.ContentDigest;
import org.modeshape.jcr.api.Binary;
Expand All @@ -63,12 +65,15 @@ public class DatastreamImpl extends FedoraResourceImpl implements Datastream {
* The JCR node for this datastream
*
* @param n an existing {@link Node}
* @throws ResourceTypeException if the node existed prior to this call but is not a datastream.
*/
public DatastreamImpl(final Node n) {
public DatastreamImpl(final Node n) throws ResourceTypeException {
super(n);

if (node.isNew()) {
initializeNewDatastreamProperties();
} else if (!hasMixin(node) && !isFrozen.apply(n)) {
throw new ResourceTypeException("Attempting to perform a datastream operation on a non-datastream resource!");
}
}

Expand All @@ -78,13 +83,15 @@ public DatastreamImpl(final Node n) {
* @param session the JCR session to use to retrieve the object
* @param path the absolute path to the object
* @param nodeType primary type to assign to node
* @throws RepositoryException
* @throws RepositoryException in the event of an exception accessing the repository, or specifically a
* ResourceTypeException if a node exists at the path but is not a datastream.
*/
public DatastreamImpl(final Session session, final String path, final String nodeType) throws RepositoryException {
super(session, path, nodeType);

if (node.isNew()) {
initializeNewDatastreamProperties();
} else if (!hasMixin(node) && !isFrozen.apply(node)) {
throw new ResourceTypeException("Attempting to perform a datastream operation on a non-datastream resource!");
}
}

Expand Down
Expand Up @@ -166,7 +166,7 @@ public Datastream getDatastream(final Session session, final String path)
* @return node as datastream
*/
@Override
public Datastream asDatastream(final Node node) {
public Datastream asDatastream(final Node node) throws RepositoryException {
return new DatastreamImpl(node);
}

Expand Down
Expand Up @@ -15,6 +15,7 @@
*/
package org.fcrepo.integration.kernel.impl.services;

import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_DATASTREAM;
import static org.fcrepo.jcr.FedoraJcrTypes.PREMIS_FILE_NAME;
import static org.jgroups.util.Util.assertEquals;
import static org.jgroups.util.Util.assertTrue;
Expand Down Expand Up @@ -178,6 +179,7 @@ public void testChecksumBlobsForValuesWithoutChecksums() throws Exception {
final FedoraObject object = objectService.createObject(session, "/testLLObject");

final Node testRandomContentNode = object.getNode().addNode("testRandomContent", NT_FILE);
testRandomContentNode.addMixin(FEDORA_DATASTREAM);
final Node testRandomContent = testRandomContentNode.addNode(JCR_CONTENT, NT_RESOURCE);
testRandomContent.setProperty(JCR_DATA,
factory.createBinary(new ByteArrayInputStream("0123456789".getBytes())));
Expand Down
Expand Up @@ -15,6 +15,34 @@
*/
package org.fcrepo.kernel.impl;

import org.apache.tika.io.IOUtils;
import org.fcrepo.jcr.FedoraJcrTypes;
import org.fcrepo.kernel.Datastream;
import org.fcrepo.kernel.FedoraObject;
import org.fcrepo.kernel.exception.InvalidChecksumException;
import org.fcrepo.kernel.exception.ResourceTypeException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.modeshape.jcr.api.ValueFactory;

import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Date;

import static org.fcrepo.kernel.impl.DatastreamImpl.hasMixin;
import static org.fcrepo.kernel.utils.TestHelpers.checksumString;
import static org.fcrepo.kernel.utils.TestHelpers.getContentNodeMock;
Expand All @@ -31,33 +59,6 @@
import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;
import static org.modeshape.jcr.api.JcrConstants.JCR_MIME_TYPE;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Date;

import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;

import org.apache.tika.io.IOUtils;
import org.fcrepo.jcr.FedoraJcrTypes;
import org.fcrepo.kernel.Datastream;
import org.fcrepo.kernel.FedoraObject;
import org.fcrepo.kernel.exception.InvalidChecksumException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.modeshape.jcr.api.ValueFactory;

/**
* <p>DatastreamImplTest class.</p>
Expand All @@ -70,6 +71,8 @@ public class DatastreamImplTest implements FedoraJcrTypes {

Datastream testObj;

String testObjPath;

@Mock
Session mockSession;

Expand All @@ -82,11 +85,15 @@ public class DatastreamImplTest implements FedoraJcrTypes {
@Mock
ValueFactory mockVF;

@Mock
NodeType mockDsNodeType;

@Before
public void setUp() {
initMocks(this);
final NodeType[] nodeTypes = new NodeType[0];
final NodeType[] nodeTypes = new NodeType[] { mockDsNodeType };
try {
when(mockDsNodeType.getName()).thenReturn(FEDORA_DATASTREAM);
when(mockDsNode.getMixinNodeTypes()).thenReturn(nodeTypes);
when(mockDsNode.getName()).thenReturn(testDsId);
when(mockDsNode.getSession()).thenReturn(mockSession);
Expand All @@ -107,6 +114,24 @@ public void tearDown() {
mockDsNode = null;
}

@Test (expected = ResourceTypeException.class)
public void testGetObjectAsDatastreamFromNode() throws ResourceTypeException {
when(mockDsNodeType.getName()).thenReturn(FEDORA_OBJECT);
new DatastreamImpl(mockDsNode);
}

@Test (expected = ResourceTypeException.class)
public void testGetObjectAsDatastreamFromPath() throws RepositoryException {
when(mockDsNodeType.getName()).thenReturn(FEDORA_OBJECT);

// Mock the current implementation of JcrTools.findOrCreateNode()
testObjPath = "/test";
when(mockSession.getRootNode()).thenReturn(mockRootNode);
when(mockRootNode.getNode("test")).thenReturn(mockDsNode);

new DatastreamImpl(mockSession, testObjPath, FEDORA_DATASTREAM);
}

@Test
public void testGetNode() {
assertEquals(testObj.getNode(), mockDsNode);
Expand Down
Expand Up @@ -82,6 +82,9 @@ public class DatastreamServiceImplTest implements FedoraJcrTypes {
@Mock
private Node mockNode;

@Mock
private NodeType mockDsNodeType;

@Mock
private Node mockContent;

Expand Down Expand Up @@ -127,7 +130,8 @@ public void testCreateDatastreamNode() throws Exception {
final Binary mockBinary = mock(Binary.class);
when(mockRoot.getNode(testPath.substring(1))).thenReturn(mockNode);
when(mockNode.getNode(JCR_CONTENT)).thenReturn(mockContent);
when(mockNode.getMixinNodeTypes()).thenReturn(new NodeType[] {});
when(mockNode.getMixinNodeTypes()).thenReturn(new NodeType[] { mockDsNodeType });
when(mockDsNodeType.getName()).thenReturn(FEDORA_DATASTREAM);
when(mockData.getBinary()).thenReturn(mockBinary);

final InputStream mockIS = mock(InputStream.class);
Expand Down
@@ -0,0 +1,39 @@
/**
* Copyright 2014 DuraSpace, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.fcrepo.kernel.exception;

import javax.jcr.RepositoryException;

/**
* An extension of RepositoryException that may be thrown when attempting a
* operation (or instantiation) of one fedora resource type (Object, Datastream)
* on a different (and incompatible) type.
*
* @author Mike Durbin
*/
public class ResourceTypeException extends RepositoryException {

private static final long serialVersionUID = 1L;

/**
* Default constructor.
*/
public ResourceTypeException(final String message) {
super(message);
}

}
Expand Up @@ -25,6 +25,7 @@

import org.fcrepo.kernel.Datastream;
import org.fcrepo.kernel.exception.InvalidChecksumException;
import org.fcrepo.kernel.exception.ResourceTypeException;
import org.fcrepo.kernel.rdf.IdentifierTranslator;
import org.fcrepo.kernel.utils.FixityResult;
import org.fcrepo.kernel.utils.iterators.RdfStream;
Expand Down Expand Up @@ -98,7 +99,7 @@ Datastream createDatastream(Session session, String dsPath, String contentType,
* @param node datastream node
* @return node as a Datastream
*/
Datastream asDatastream(Node node);
Datastream asDatastream(Node node) throws ResourceTypeException, RepositoryException;

/**
* Get the fixity results for the datastream as a RDF Dataset
Expand Down

0 comments on commit 2e16f82

Please sign in to comment.