Skip to content

Commit

Permalink
Separate SWORD protocol from Fedora provider code
Browse files Browse the repository at this point in the history
  • Loading branch information
claussni committed Sep 26, 2015
1 parent ed19d74 commit 5c1d242
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/main/java/org/fcrepo/sword/http/SWORDWebResource.java
Expand Up @@ -16,7 +16,7 @@
package org.fcrepo.sword.http;

import org.apache.abdera.model.Service;
import org.fcrepo.sword.service.SWORDProviderService;
import org.fcrepo.sword.provider.SWORDServiceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;

Expand All @@ -32,7 +32,7 @@
public class SWORDWebResource {

@Autowired
private SWORDProviderService providerService;
private SWORDServiceProvider providerService;

/**
* @return Returns a SWORD service document
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/org/fcrepo/sword/protocol/SWORDProtocol.java
@@ -0,0 +1,31 @@
/**
* 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.sword.protocol;

/**
* Defines SWORD protocol related namespaces and constants
*
* @author claussni
*/
public class SWORDProtocol {
public static final String SWORD_NAMESPACE = "http://purl.org/net/sword/";
public static final String SWORD_TERMS_NAMESPACE = "http://purl.org/net/sword/terms/";
public static final String SWORD_VERSION = "2.0";

private SWORDProtocol() {
// Utility classes should not have a public or default constructor.
}
}
@@ -0,0 +1,107 @@
/**
* 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.sword.protocol;

import org.apache.abdera.Abdera;
import org.apache.abdera.model.Service;
import org.fcrepo.kernel.api.models.Container;
import org.fcrepo.kernel.api.models.FedoraResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.jcr.Value;

import static org.fcrepo.sword.protocol.SWORDProtocol.SWORD_TERMS_NAMESPACE;
import static org.fcrepo.sword.protocol.SWORDProtocol.SWORD_VERSION;

/**
* Builder for a SWORD service document using Abdera ATOM library
*
* @author claussni
*/
public class SWORDServiceDocumentBuilder {

private Abdera abdera;
private Integer maxUploadSize;
private Container workspaces;
private Logger log;

/**
* Create a new builder
*
* @param abdera Abdera implementation to use
* @param log Logger implementation to use. If none is given, a default logger for this class is used.
*/
public SWORDServiceDocumentBuilder(final Abdera abdera, final Logger log) {
this.abdera = abdera;
this.log = (log == null) ? LoggerFactory.getLogger(SWORDServiceDocumentBuilder.class) : log;
}

/**
* Set the maxUploadSize parameter
*
* @param swordMaxUploadSizeKb Maximum size of uploads in kilobytes
* @return The builder object
*/
public SWORDServiceDocumentBuilder maxUploadSize(final Integer swordMaxUploadSizeKb) {
this.maxUploadSize = swordMaxUploadSizeKb;
return this;
}

/**
* Set the Fedora container resource containing the SWORD workspace nodes
*
* @param workspaces Container with workspace nodes
* @return The builder object
*/
public SWORDServiceDocumentBuilder workspacesContainer(final Container workspaces) {
this.workspaces = workspaces;
return this;
}

/**
* Build and return the service document containing the configured parameters and detected workspaces
*
* @return A SWORD service document
*/
public Service serviceDocument() {
final Service service = abdera.newService();
service.addSimpleExtension(SWORD_TERMS_NAMESPACE, "version", "sword", SWORD_VERSION);
service.addSimpleExtension(SWORD_TERMS_NAMESPACE, "maxUploadSize", "sword", String.valueOf(maxUploadSize));
workspaces.getChildren().forEachRemaining(fedoraResource -> addWorkspace(service, fedoraResource));
return service;
}

private void addWorkspace(final Service service, final FedoraResource fedoraResource) {
try {
final Value[] dcTitles = fedoraResource.getProperty("dc:title").getValues();
if (dcTitles.length > 0) {
try {
final String title = dcTitles[0].getString();
if (!title.isEmpty()) {
service.addWorkspace(title);
}
} catch (IndexOutOfBoundsException | NullPointerException e) {
log.warn("Found workspace container without dc:title property: {}", fedoraResource.getPath());
}
}
} catch (RepositoryException e) {
log.warn("Found workspace container with invalid dc:title property: {}", fedoraResource.getPath());
}
}

}
Expand Up @@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fcrepo.sword.service;
package org.fcrepo.sword.provider;

import org.apache.abdera.Abdera;
import org.apache.abdera.model.Service;
import org.fcrepo.http.commons.session.SessionFactory;
import org.fcrepo.kernel.api.RdfLexicon;
import org.fcrepo.kernel.api.models.Container;
import org.fcrepo.kernel.api.models.FedoraResource;
import org.fcrepo.kernel.api.services.ContainerService;
import org.fcrepo.kernel.api.services.NodeService;
import org.fcrepo.kernel.api.utils.NamespaceTools;
import org.fcrepo.sword.protocol.SWORDServiceDocumentBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -33,33 +33,30 @@
import javax.jcr.NamespaceRegistry;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import java.util.Map;

import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
import static java.util.Collections.emptyMap;
import static org.fcrepo.kernel.modeshape.rdf.converters.PropertyConverter.getPropertyNameFromPredicate;
import static org.fcrepo.sword.protocol.SWORDProtocol.SWORD_NAMESPACE;

/**
* Implements all protocol related methods to be executed via {@link org.fcrepo.sword.http.SWORDWebResource}
*
* @author claussni
*/
@Component
public class SWORDProviderService {
public class SWORDServiceProvider {

public static final String SWORD_ROOT_PATH = "/sword";
public static final String SWORD_COLLECTIONS_PATH = SWORD_ROOT_PATH + "/collections";
public static final String SWORD_WORKSPACES_PATH = SWORD_ROOT_PATH + "/workspaces";

private static final String NS_SWORD = "http://purl.org/net/sword/";
private static final String NS_SWORD_TERMS = "http://purl.org/net/sword/terms/";
private static final String RDF_PREFIX = "sword";
private static final String SWORD_ROOT_LABEL = "SWORD root";
private static final String SWORD_VERSION = "2.0";
private static final Integer SWORD_MAX_UPLOAD_SIZE_KB = Integer.MAX_VALUE;

private static final Logger log = LoggerFactory.getLogger(SWORDProviderService.class);
private static final Logger log = LoggerFactory.getLogger(SWORDServiceProvider.class);
private final Abdera abdera = new Abdera();

@Autowired
Expand All @@ -74,39 +71,20 @@ public class SWORDProviderService {
private Container workspaces;

/**
* Build and return a SWORD service document.
* Build and return a SWORD service document
*
* @return SWORD service document
*/
public Service serviceDocument() {
final Service service = abdera.newService();
service.addSimpleExtension(NS_SWORD_TERMS, "version", "sword", SWORD_VERSION);
service.addSimpleExtension(NS_SWORD_TERMS, "maxUploadSize", "sword", String.valueOf(SWORD_MAX_UPLOAD_SIZE_KB));
workspaces.getChildren().forEachRemaining(fedoraResource -> addWorkspaces(service, fedoraResource));
return service;
}

private void addWorkspaces(final Service service, final FedoraResource fedoraResource) {
try {
final Value[] dcTitles = fedoraResource.getProperty("dc:title").getValues();
if (dcTitles.length > 0) {
try {
final String title = dcTitles[0].getString();
if (!title.isEmpty()) {
service.addWorkspace(title);
}
} catch (IndexOutOfBoundsException | NullPointerException e) {
log.warn("Found workspace container without dc:title property: {}", fedoraResource.getPath());
}
}
} catch (RepositoryException e) {
log.warn("Found workspace container with invalid dc:title property: {}", fedoraResource.getPath());
}
final SWORDServiceDocumentBuilder sb = new SWORDServiceDocumentBuilder(abdera, log)
.maxUploadSize(SWORD_MAX_UPLOAD_SIZE_KB)
.workspacesContainer(workspaces);
return sb.serviceDocument();
}

@PostConstruct
private void init() {
final Session session = sessionFactory.getInternalSession();
final Session session = sessionFactory.getInternalSession();
final NamespaceRegistry namespaceRegistry = NamespaceTools.getNamespaceRegistry(session);

ensureSwordNamespaceRegistration(namespaceRegistry);
Expand All @@ -121,10 +99,10 @@ private void init() {

private void ensureSwordNamespaceRegistration(final NamespaceRegistry namespaceRegistry) {
try {
namespaceRegistry.registerNamespace(RDF_PREFIX, NS_SWORD);
namespaceRegistry.registerNamespace(RDF_PREFIX, SWORD_NAMESPACE);
} catch (RepositoryException e) {
throw new RuntimeException(
String.format("Failed to register namespace %s:%s", RDF_PREFIX, NS_SWORD), e);
String.format("Failed to register namespace %s:%s", RDF_PREFIX, SWORD_NAMESPACE), e);
}
}

Expand Down
Expand Up @@ -24,7 +24,7 @@
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.fcrepo.sword.service.SWORDProviderService;
import org.fcrepo.sword.provider.SWORDServiceProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -41,7 +41,7 @@
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring-test/test-container.xml")
public abstract class BaseProviderServiceIT {
public abstract class BaseServiceProviderIT {

protected static final int SERVER_PORT = Integer.parseInt(System
.getProperty("fcrepo.dynamic.test.port", "8080"));
Expand Down Expand Up @@ -83,7 +83,7 @@ protected HttpResponse createWorkspaceNode(final String title) throws IOExceptio
final HttpPost post = new HttpPost(String.format("http://%s:%s/%s/",
HOSTNAME,
SERVER_PORT,
SWORDProviderService.SWORD_WORKSPACES_PATH));
SWORDServiceProvider.SWORD_WORKSPACES_PATH));
post.setHeader("Content-Type", "text/turtle");
post.setEntity(new StringEntity(
String.format("PREFIX dc: <http://purl.org/dc/elements/1.1/>\n" +
Expand Down
Expand Up @@ -17,7 +17,7 @@

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.fcrepo.sword.service.SWORDProviderService;
import org.fcrepo.sword.provider.SWORDServiceProvider;
import org.junit.Test;

import java.io.IOException;
Expand All @@ -27,14 +27,14 @@
/**
* @author claussni
*/
public class ContainerInitializationIT extends BaseProviderServiceIT {
public class ContainerInitializationIT extends BaseServiceProviderIT {

@Test
public void initializesRootContainer() throws IOException {
final HttpGet get = new HttpGet(String.format("http://%s:%s/%s",
HOSTNAME,
SERVER_PORT,
SWORDProviderService.SWORD_ROOT_PATH));
SWORDServiceProvider.SWORD_ROOT_PATH));
final HttpResponse response = httpClient.execute(get);
assertStatusCode(200, response);
}
Expand All @@ -44,7 +44,7 @@ public void initializesWorkspacesContainer() throws IOException {
final HttpGet get = new HttpGet(String.format("http://%s:%s/%s",
HOSTNAME,
SERVER_PORT,
SWORDProviderService.SWORD_WORKSPACES_PATH));
SWORDServiceProvider.SWORD_WORKSPACES_PATH));
final HttpResponse response = httpClient.execute(get);
assertStatusCode(200, response);
}
Expand All @@ -54,7 +54,7 @@ public void initializesCollectionsContainer() throws IOException {
final HttpGet get = new HttpGet(String.format("http://%s:%s/%s",
HOSTNAME,
SERVER_PORT,
SWORDProviderService.SWORD_COLLECTIONS_PATH));
SWORDServiceProvider.SWORD_COLLECTIONS_PATH));
final HttpResponse response = httpClient.execute(get);
assertStatusCode(200, response);
}
Expand Down
Expand Up @@ -31,7 +31,7 @@
/**
* @author claussni
*/
public class ServiceDocumentIT extends BaseProviderServiceIT {
public class ServiceDocumentIT extends BaseServiceProviderIT {

@Test
public void returnsAtomServiceDocumentMediaType() throws IOException {
Expand Down

0 comments on commit 5c1d242

Please sign in to comment.