Skip to content

Commit

Permalink
Add delete, copy, move functionality to FedoraResourceImpl
Browse files Browse the repository at this point in the history
- Add delete method to FedoraResourceImpl.java
- Add specific exception to be thrown when creatng resource that exists
- Add forceDelete() method to remove resource and tombstone
- Implemented copy and move method in FedoraResourceImpl
- Add an implementation of HttpCopy and HttpMove (missing from HTTP Client)
- Add forceMove() to be coherent with other methods that manipulate tombstones

Resolves: https://jira.duraspace.org/browse/FCREPO-1632
  • Loading branch information
sleroux-keep authored and Andrew Woods committed Jul 14, 2015
1 parent 0375aec commit 6f485d8
Show file tree
Hide file tree
Showing 10 changed files with 535 additions and 28 deletions.
Expand Up @@ -40,7 +40,7 @@
* @since 2014-08-11
*/
public class FedoraObjectImpl extends FedoraResourceImpl implements FedoraObject {
private final static Node binaryType = NodeFactory.createLiteral("fedora:binary");
private final static Node binaryType = NodeFactory.createLiteral("fedora:Binary");

/**
* Constructor for FedoraObjectImpl
Expand Down
Expand Up @@ -16,12 +16,14 @@
package org.fcrepo.client.impl;

import com.hp.hpl.jena.graph.Triple;

import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.fcrepo.client.AlreadyExistsException;
import org.fcrepo.client.FedoraContent;
import org.fcrepo.client.FedoraDatastream;
import org.fcrepo.client.FedoraException;
Expand Down Expand Up @@ -147,7 +149,7 @@ public FedoraDatastream createDatastream(final String path, final FedoraContent
throw new ForbiddenException("request to create resource " + uri + " is not authorized.");
} else if (statusCode == SC_CONFLICT) {
LOGGER.error("resource {} already exists", uri);
throw new FedoraException("resource " + uri + " already exists");
throw new AlreadyExistsException("resource " + uri + " already exists");
} else {
LOGGER.error("error creating resource {}: {} {}", uri, statusCode, status.getReasonPhrase());
throw new FedoraException("error retrieving resource " + uri + ": " + statusCode + " " +
Expand Down Expand Up @@ -206,7 +208,7 @@ public FedoraObject createObject(final String path) throws FedoraException {
throw new ForbiddenException("request to create resource " + uri + " is not authorized.");
} else if (statusCode == SC_CONFLICT) {
LOGGER.error("resource {} already exists", uri);
throw new FedoraException("resource " + uri + " already exists");
throw new AlreadyExistsException("resource " + uri + " already exists");
} else {
LOGGER.error("error creating resource {}: {} {}", uri, statusCode, status.getReasonPhrase());
throw new FedoraException("error retrieving resource " + uri + ": " + statusCode + " " +
Expand Down
Expand Up @@ -19,7 +19,6 @@
import static org.apache.http.HttpStatus.SC_FORBIDDEN;
import static org.apache.http.HttpStatus.SC_NO_CONTENT;
import static org.apache.http.HttpStatus.SC_NOT_FOUND;

import static org.slf4j.LoggerFactory.getLogger;

import java.io.IOException;
Expand All @@ -32,23 +31,22 @@
import java.util.Iterator;
import java.util.Set;

import org.apache.http.client.methods.HttpPost;
import org.apache.jena.atlas.lib.NotImplemented;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;

import org.fcrepo.client.FedoraException;
import org.fcrepo.client.FedoraRepository;
import org.fcrepo.client.FedoraResource;
import org.fcrepo.client.ForbiddenException;
import org.fcrepo.client.NotFoundException;
import org.fcrepo.client.ReadOnlyException;
import org.fcrepo.client.utils.HttpCopy;
import org.fcrepo.client.utils.HttpHelper;
import org.fcrepo.client.utils.HttpMove;
import org.fcrepo.kernel.RdfLexicon;

import org.slf4j.Logger;

import com.hp.hpl.jena.graph.Graph;
Expand Down Expand Up @@ -76,6 +74,8 @@ public class FedoraResourceImpl implements FedoraResource {

protected String path = null;

protected String oldPath = null;

protected Node subject = null;

protected Graph graph;
Expand All @@ -97,15 +97,118 @@ public FedoraResourceImpl(final FedoraRepository repository, final HttpHelper ht
}

@Override
public void copy(final String destination) throws ReadOnlyException {
// TODO Auto-generated method stub
throw new NotImplemented("Method copy(final String destination) is not implemented.");
public void copy(final String destination) throws FedoraException {

final HttpCopy copy = httpHelper.createCopyMethod(path,destination);

try {
final HttpResponse response = httpHelper.execute( copy );
final StatusLine status = response.getStatusLine();
final String uri = copy.getURI().toString();

if (status.getStatusCode() == HttpStatus.SC_CREATED) { // Created
LOGGER.debug("resource successfully copied from " + path + " to " + destination, uri);
} else if (status.getStatusCode() == HttpStatus.SC_CONFLICT) { // Source path doesn't exists
LOGGER.error("error copying resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error copying resource " + uri + ": " + status.getStatusCode() + " " +
status.getReasonPhrase());
} else if (status.getStatusCode() == HttpStatus.SC_PRECONDITION_FAILED) { // Destination path already exists
LOGGER.error("error copying resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error copying resource " + uri + ": " + status.getStatusCode() + " " +
status.getReasonPhrase());
} else if (status.getStatusCode() == HttpStatus.SC_BAD_GATEWAY) {
// Destination URI isn't a valid resource path
LOGGER.error("error copying resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error copying resource " + uri + ": " + status.getStatusCode() + " " +
status.getReasonPhrase());
}
} catch (final FedoraException e) {
throw e;
} catch (final Exception e) {
LOGGER.error("could not encode URI parameter", e);
throw new FedoraException(e);
} finally {
copy.releaseConnection();
}
}

@Override
public void delete() throws FedoraException {
final HttpDelete delete = httpHelper.createDeleteMethod(path);

try {
final HttpResponse response = httpHelper.execute( delete );
final StatusLine status = response.getStatusLine();
final String uri = delete.getURI().toString();

if ( status.getStatusCode() == SC_NO_CONTENT) {
LOGGER.debug("triples updated successfully for resource {}", uri);
} else if ( status.getStatusCode() == SC_NOT_FOUND) {
LOGGER.error("resource {} does not exist, cannot update", uri);
throw new NotFoundException("resource " + uri + " does not exist, cannot update");
} else {
LOGGER.error("error updating resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error updating resource " + uri + ": " + status.getStatusCode() + " " +
status.getReasonPhrase());
}
} catch (final FedoraException e) {
throw e;
} catch (final Exception e) {
LOGGER.error("Error executing request", e);
throw new FedoraException(e);
} finally {
delete.releaseConnection();
}
}

@Override
public void delete() throws ReadOnlyException {
// TODO Auto-generated method stub
throw new NotImplemented("Method delete() is not implemented.");
public void forceDelete() throws FedoraException {
delete();
removeTombstone();
}

/**
* Remove tombstone (for the current path)
*/
public void removeTombstone() throws FedoraException {
removeTombstone(path);
}


/**
* Remove tombstone located at given path
*/
public void removeTombstone(final String path) throws FedoraException {
final HttpDelete delete = httpHelper.createDeleteMethod(path + "/fcr:tombstone");

try {
final HttpResponse response = httpHelper.execute( delete );
final StatusLine status = response.getStatusLine();
final String uri = delete.getURI().toString();

if ( status.getStatusCode() == SC_NO_CONTENT) {
LOGGER.debug("triples updated successfully for resource {}", uri);
} else if ( status.getStatusCode() == SC_NOT_FOUND) {
LOGGER.error("resource {} does not exist, cannot update", uri);
throw new NotFoundException("resource " + uri + " does not exist, cannot update");
} else {
LOGGER.error("error updating resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error updating resource " + uri + ": " + status.getStatusCode() + " " +
status.getReasonPhrase());
}
} catch (final FedoraException e) {
throw e;
} catch (final Exception e) {
LOGGER.error("Error executing request", e);
throw new FedoraException(e);
} finally {
delete.releaseConnection();
}
}

@Override
Expand Down Expand Up @@ -160,9 +263,52 @@ public Long getSize() {
}

@Override
public void move(final String destination) throws ReadOnlyException {
// TODO Auto-generated method stub
throw new NotImplemented("Method move(final String destination) is not implemented.");
public void move(final String destination) throws FedoraException {
final HttpMove move = httpHelper.createMoveMethod(path,destination);

try {
final HttpResponse response = httpHelper.execute( move );
final StatusLine status = response.getStatusLine();
final String uri = move.getURI().toString();

if (status.getStatusCode() == HttpStatus.SC_CREATED) { // Created
LOGGER.debug("resource successfully moved from " + path + " to " + destination, uri);
oldPath = path;
path = destination;
subject = NodeFactory.createURI(repository.getRepositoryUrl() + path);
} else if (status.getStatusCode() == HttpStatus.SC_CONFLICT) { // Source path doesn't exists
LOGGER.error("error moving resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error moving resource " + uri + ": " + status.getStatusCode() +
" " + status.getReasonPhrase());
} else if (status.getStatusCode() == HttpStatus.SC_PRECONDITION_FAILED) {
// Destination path already exists
LOGGER.error("error moving resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error moving resource " + uri + ": " + status.getStatusCode() + " " +
status.getReasonPhrase());
} else if (status.getStatusCode() == HttpStatus.SC_BAD_GATEWAY) {
// Destination URI isn't a valid resource path
LOGGER.error("error moving resource {}: {} {}", uri, status.getStatusCode(),
status.getReasonPhrase());
throw new FedoraException("error moving resource " + uri + ": " + status.getStatusCode() + " " +
status.getReasonPhrase());
}
} catch (final FedoraException e) {
oldPath = null;
throw e;
} catch (final Exception e) {
LOGGER.error("could not encode URI parameter", e);
throw new FedoraException(e);
} finally {
move.releaseConnection();
}
}

@Override
public void forceMove(final String destination) throws FedoraException {
move(destination);
removeTombstone(oldPath);
}

@Override
Expand Down
@@ -0,0 +1,63 @@
/**
* 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.client.utils;

import java.net.URI;

import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;

/**
* HTTP copy
*
* @author sleroux
* @since 2015-06-03
**/
public class HttpCopy extends HttpEntityEnclosingRequestBase {

/**
* Create an HTTP COPY request.
*
* @param source
* Source URL.
* @param destination
* Destination URL.
**/
public HttpCopy(final URI source, final URI destination) {
this.setHeader(HttpHeaders.DESTINATION, destination.toASCIIString());
this.setURI(source);
}

/**
* Create an HTTP COPY request.
*
* @param source
* Source String URL.
* @param destination
* Destination String URL.
**/
public HttpCopy(final String source, final String destination) {
this(URI.create(source), URI.create(destination));
}

/**
* Returns the request method.
**/
@Override
public String getMethod() {
return "COPY";
}
}
Expand Up @@ -50,6 +50,7 @@
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPatch;
Expand Down Expand Up @@ -201,6 +202,15 @@ public HttpGet createGetMethod(final String path, final Map<String, List<String>
return new HttpGet(repositoryURL + path + queryString(params));
}

/**
* Create DELETE method
* @param path Resource path, relative to repository baseURL
* @return DELETE method
**/
public HttpDelete createDeleteMethod(final String path) {
return new HttpDelete(repositoryURL + path);
}

/**
* Create a request to update triples with SPARQL Update.
* @param path The datastream path.
Expand Down Expand Up @@ -359,4 +369,24 @@ public FedoraResourceImpl loadProperties( final FedoraResourceImpl resource ) th
}
}

/**
* Create COPY method
* @param sourcePath Source path, relative to repository baseURL
* @param destinationPath Destination path, relative to repository baseURL
* @return COPY method
**/
public HttpCopy createCopyMethod(final String sourcePath, final String destinationPath) {
return new HttpCopy(repositoryURL + sourcePath, repositoryURL + destinationPath);
}

/**
* Create MOVE method
* @param sourcePath Source path, relative to repository baseURL
* @param destinationPath Destination path, relative to repository baseURL
* @return MOVE method
**/
public HttpMove createMoveMethod(final String sourcePath, final String destinationPath) {
return new HttpMove(repositoryURL + sourcePath, repositoryURL + destinationPath);
}

}

0 comments on commit 6f485d8

Please sign in to comment.