Skip to content

Commit

Permalink
POST/PATCH must advertise constraints if triples not persisted
Browse files Browse the repository at this point in the history
- Create ConstraintViolationException subclass of MalformedRdfException
- Create OutOfDomainSubjectException subclass of ConstraintViolationException
- Move ServerManagedPropertyException to subclass of ConstraintViolationException
- Add OutOfDomainSubjectExceptionMapper, ConstraintViolationExceptionMapper
- Change some Exceptions thrown at JcrPropertyStatementListener
- Propagate out of  PersistingRdfStreamConsumer and FedoraResourceImpl
- Add ManagedTypeException, Mapper and throw from PersistingRdfStreamConsumer
- Rename ManagedTypeException to ServerManagedTypeException
- Make ConstraintExceptionMapper superclass.

Resolves to: https://jira.duraspace.org/browse/FCREPO-1418
  • Loading branch information
whikloj authored and Andrew Woods committed Jun 29, 2015
1 parent f13ca21 commit 447e56a
Show file tree
Hide file tree
Showing 23 changed files with 704 additions and 28 deletions.
Expand Up @@ -31,6 +31,7 @@
import static java.util.regex.Pattern.compile;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.CONFLICT;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.Status.NOT_MODIFIED;
import static javax.ws.rs.core.Response.Status.NO_CONTENT;
Expand All @@ -51,6 +52,7 @@
import static org.fcrepo.kernel.FedoraJcrTypes.FEDORA_CONTAINER;
import static org.fcrepo.kernel.FedoraJcrTypes.ROOT;
import static org.fcrepo.kernel.RdfLexicon.BASIC_CONTAINER;
import static org.fcrepo.kernel.RdfLexicon.CONSTRAINED_BY;
import static org.fcrepo.kernel.RdfLexicon.CONTAINS;
import static org.fcrepo.kernel.RdfLexicon.DC_TITLE;
import static org.fcrepo.kernel.RdfLexicon.DIRECT_CONTAINER;
Expand Down Expand Up @@ -86,6 +88,7 @@
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -1557,6 +1560,8 @@ public void testUpdateObjectGraphWithProblems() throws Exception {

final HttpResponse createResponse = createObject("");
final String subjectURI = createResponse.getFirstHeader("Location").getValue();
final Link exLink = Link.fromUri(new URI(serverAddress +
"static/constraints/ServerManagedPropertyException.rdf")).rel(CONSTRAINED_BY.getURI()).build();

final HttpPatch patchObjMethod = new HttpPatch(subjectURI);
patchObjMethod.addHeader("Content-Type", "application/sparql-update");
Expand All @@ -1568,12 +1573,14 @@ public void testUpdateObjectGraphWithProblems() throws Exception {
patchObjMethod.setEntity(e);
final HttpResponse response = client.execute(patchObjMethod);

if (response.getStatusLine().getStatusCode() != BAD_REQUEST.getStatusCode()
if (response.getStatusLine().getStatusCode() != CONFLICT.getStatusCode()
&& response.getEntity() != null) {
final String content = EntityUtils.toString(response.getEntity());
logger.trace("Got unexpected update response:\n" + content);
}
assertEquals(BAD_REQUEST.getStatusCode(), response.getStatusLine().getStatusCode());

assertEquals(CONFLICT.getStatusCode(), response.getStatusLine().getStatusCode());
assertEquals(exLink.toString(), response.getFirstHeader("Link").getValue().toString());

}

Expand All @@ -1597,7 +1604,7 @@ public void testRepeatedPut() throws Exception {

final HttpPut secondPut = new HttpPut(serverAddress + pid);
secondPut.setHeader("Content-Type", "text/turtle");
assertEquals(400, getStatus(secondPut));
assertEquals(CONFLICT.getStatusCode(), getStatus(secondPut));
}

@Test
Expand Down
@@ -0,0 +1,54 @@
/**
* Copyright 2015 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.http.commons.exceptionhandlers;

import static org.fcrepo.kernel.RdfLexicon.CONSTRAINED_BY;

import javax.ws.rs.core.Link;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.ExceptionMapper;

import org.fcrepo.kernel.exception.ConstraintViolationException;

/**
* Abstract class for constraint violation subclasses
*
* @author whikloj
* @since 2015-06-24
* @param <T> Throwable subclass of ConstraintViolationException
*/
public abstract class ConstraintExceptionMapper<T extends ConstraintViolationException> implements ExceptionMapper<T> {

/**
* Where the RDF exception files sit.
*/
private static final String CONSTRAINT_DIR = "/static/constraints/";

/**
* Creates a constrainedBy link header with the appropriate RDF URL for the exception.
*
* @param e ConstraintViolationException Exception which implements the buildContraintUri method.
* @param uriInfo UriInfo UriInfo from the ExceptionMapper.
* @return Link A http://www.w3.org/ns/ldp#constrainedBy link header
*/
public static Link buildConstraintLink(final ConstraintViolationException e, final UriInfo uriInfo) {
final String constraintURI = uriInfo == null ? "" : String.format("%s://%s%s%s.rdf",
uriInfo.getBaseUri().getScheme(), uriInfo.getBaseUri().getAuthority(),
CONSTRAINT_DIR, e.getClass().toString().substring(e.getClass().toString().lastIndexOf('.') + 1));
return Link.fromUri(constraintURI).rel(CONSTRAINED_BY.getURI()).build();
}

}
@@ -0,0 +1,47 @@
/**
* Copyright 2015 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.http.commons.exceptionhandlers;

import static javax.ws.rs.core.Response.status;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;

import org.fcrepo.kernel.exception.ConstraintViolationException;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;

/**
* @author whikloj
* @since 2015-06-01
*/
@Provider
public class ConstraintViolationExceptionMapper extends ConstraintExceptionMapper<ConstraintViolationException> {

@Context
private UriInfo uriInfo;

@Override
public Response toResponse(final ConstraintViolationException e) {

final Link link = buildConstraintLink(e, uriInfo);
final String msg = e.getMessage();
return status(BAD_REQUEST).entity(msg).links(link).build();
}

}
@@ -0,0 +1,47 @@
/**
* Copyright 2015 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.http.commons.exceptionhandlers;

import static javax.ws.rs.core.Response.status;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;

import org.fcrepo.kernel.exception.OutOfDomainSubjectException;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;

/**
* @author whikloj
* @since 2015-05-29
*/
@Provider
public class OutOfDomainSubjectExceptionMapper extends ConstraintExceptionMapper<OutOfDomainSubjectException> {

@Context
private UriInfo uriInfo;

@Override
public Response toResponse(final OutOfDomainSubjectException e) {

final Link link = buildConstraintLink(e, uriInfo);
final String msg = e.getMessage();
return status(BAD_REQUEST).entity(msg).links(link).build();
}

}
Expand Up @@ -17,22 +17,30 @@

import org.fcrepo.kernel.exception.ServerManagedPropertyException;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;

import static javax.ws.rs.core.Response.Status.CONFLICT;
import static javax.ws.rs.core.Response.status;

/**
* @author cabeer
* @author whikloj
* @since 10/1/14
*/
@Provider
public class ServerManagedPropertyExceptionMapper implements ExceptionMapper<ServerManagedPropertyException> {
public class ServerManagedPropertyExceptionMapper extends ConstraintExceptionMapper<ServerManagedPropertyException> {

@Context
private UriInfo uriInfo;

@Override
public Response toResponse(final ServerManagedPropertyException e) {
return status(CONFLICT).entity(e.getMessage()).build();
final Link link = buildConstraintLink(e, uriInfo);
final String msg = e.getMessage();
return status(CONFLICT).entity(msg).links(link).build();
}
}
@@ -0,0 +1,45 @@
/**
* Copyright 2015 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.http.commons.exceptionhandlers;

import static javax.ws.rs.core.Response.status;
import static javax.ws.rs.core.Response.Status.CONFLICT;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;

import org.fcrepo.kernel.exception.ServerManagedTypeException;

/**
* @author whikloj
* @since 2015-06-02
*/
@Provider
public class ServerManagedTypeExceptionMapper extends ConstraintExceptionMapper<ServerManagedTypeException> {

@Context
private UriInfo uriInfo;

@Override
public Response toResponse(final ServerManagedTypeException e) {
final Link link = buildConstraintLink(e, uriInfo);
final String msg = e.getMessage();
return status(CONFLICT).entity(msg).links(link).build();
}
}
@@ -0,0 +1,67 @@
/**
* Copyright 2015 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.http.commons.exceptionhandlers;

import java.net.URI;
import java.net.URISyntaxException;

import javax.jcr.RepositoryException;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.UriInfo;

import org.fcrepo.kernel.exception.ConstraintViolationException;

import static org.fcrepo.http.commons.test.util.TestHelpers.getUriInfoImpl;
import static org.fcrepo.kernel.RdfLexicon.CONSTRAINED_BY;
import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

/**
* ConstraintViolationExceptionMapperTest
*
* @author whikloj
* @since 2015-06-22
*/
@RunWith(MockitoJUnitRunner.class)
public class ConstraintViolationExceptionMapperTest {

private UriInfo mockInfo;

@Mock
private ConstraintViolationExceptionMapper mapper;

@Before
public void setUp() throws RepositoryException, URISyntaxException {
this.mockInfo = getUriInfoImpl();
}

@Test
public void testBuildConstraintLink() {
final URI testLink = URI.create("http://localhost/static/constraints/ConstraintViolationException.rdf");

final ConstraintViolationException ex = new ConstraintViolationException("This is an error.");

final Link link = ConstraintViolationExceptionMapper.buildConstraintLink(ex, mockInfo);

assertEquals(link.getRel(), CONSTRAINED_BY.getURI());
assertEquals(link.getUri(), testLink);
}
}
Expand Up @@ -67,6 +67,7 @@
import org.fcrepo.kernel.models.NonRdfSourceDescription;
import org.fcrepo.kernel.models.FedoraBinary;
import org.fcrepo.kernel.models.FedoraResource;
import org.fcrepo.kernel.exception.ConstraintViolationException;
import org.fcrepo.kernel.exception.MalformedRdfException;
import org.fcrepo.kernel.exception.PathNotFoundRuntimeException;
import org.fcrepo.kernel.exception.RepositoryRuntimeException;
Expand Down Expand Up @@ -545,6 +546,8 @@ public void replaceProperties(final IdentifierConverter<Resource, FedoraResource
try {
new RdfRemover(idTranslator, getSession(), replacementStream
.withThisContext(differencer)).consume();
} catch (final ConstraintViolationException e) {
throw e;
} catch (final MalformedRdfException e) {
exceptions.append(e.getMessage());
exceptions.append("\n");
Expand All @@ -553,6 +556,8 @@ public void replaceProperties(final IdentifierConverter<Resource, FedoraResource
try {
new RdfAdder(idTranslator, getSession(), replacementStream
.withThisContext(differencer.notCommon())).consume();
} catch (final ConstraintViolationException e) {
throw e;
} catch (final MalformedRdfException e) {
exceptions.append(e.getMessage());
}
Expand Down

0 comments on commit 447e56a

Please sign in to comment.