001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.sword.provider;
017
018import org.apache.abdera.Abdera;
019import org.apache.abdera.model.Service;
020import org.fcrepo.http.commons.session.SessionFactory;
021import org.fcrepo.kernel.api.RdfLexicon;
022import org.fcrepo.kernel.api.models.Container;
023import org.fcrepo.kernel.api.services.ContainerService;
024import org.fcrepo.kernel.api.services.NodeService;
025import org.fcrepo.kernel.api.utils.NamespaceTools;
026import org.fcrepo.sword.protocol.SWORDServiceDocumentBuilder;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029import org.springframework.beans.factory.annotation.Autowired;
030import org.springframework.stereotype.Component;
031
032import javax.annotation.PostConstruct;
033import javax.jcr.NamespaceRegistry;
034import javax.jcr.RepositoryException;
035import javax.jcr.Session;
036import java.util.Map;
037
038import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
039import static java.util.Collections.emptyMap;
040import static org.fcrepo.kernel.modeshape.rdf.converters.PropertyConverter.getPropertyNameFromPredicate;
041import static org.fcrepo.sword.protocol.SWORDProtocol.SWORD_NAMESPACE;
042
043/**
044 * Implements all protocol related methods to be executed via {@link org.fcrepo.sword.http.SWORDWebResource}
045 *
046 * @author claussni
047 */
048@Component
049public class SWORDServiceProvider {
050
051    public static final String SWORD_ROOT_PATH        = "/sword";
052    public static final String SWORD_COLLECTIONS_PATH = SWORD_ROOT_PATH + "/collections";
053    public static final String SWORD_WORKSPACES_PATH  = SWORD_ROOT_PATH + "/workspaces";
054
055    private static final String  RDF_PREFIX               = "sword";
056    private static final String  SWORD_ROOT_LABEL         = "SWORD root";
057    private static final Integer SWORD_MAX_UPLOAD_SIZE_KB = Integer.MAX_VALUE;
058
059    private static final Logger log    = LoggerFactory.getLogger(SWORDServiceProvider.class);
060    private final        Abdera abdera = new Abdera();
061
062    @Autowired
063    private SessionFactory sessionFactory;
064
065    @Autowired
066    private NodeService nodeService;
067
068    @Autowired
069    private ContainerService containerService;
070
071    private Container workspaces;
072
073    /**
074     * Build and return a SWORD service document
075     *
076     * @return SWORD service document
077     */
078    public Service serviceDocument() {
079        final SWORDServiceDocumentBuilder sb = new SWORDServiceDocumentBuilder(abdera, log)
080                .maxUploadSize(SWORD_MAX_UPLOAD_SIZE_KB)
081                .workspacesContainer(workspaces);
082        return sb.serviceDocument();
083    }
084
085    @PostConstruct
086    private void init() {
087        final Session session = sessionFactory.getInternalSession();
088        final NamespaceRegistry namespaceRegistry = NamespaceTools.getNamespaceRegistry(session);
089
090        ensureSwordNamespaceRegistration(namespaceRegistry);
091
092        final Container root = getContainer(session, SWORD_ROOT_PATH, SWORD_ROOT_LABEL);
093        ensureProperty(namespaceRegistry, root,
094                RdfLexicon.FEDORA_CONFIG_NAMESPACE + "maxUploadSizeInKb", SWORD_MAX_UPLOAD_SIZE_KB);
095
096        workspaces = getContainer(session, SWORD_WORKSPACES_PATH, "SWORD workspaces");
097        getContainer(session, SWORD_COLLECTIONS_PATH, "SWORD collections");
098    }
099
100    private void ensureSwordNamespaceRegistration(final NamespaceRegistry namespaceRegistry) {
101        try {
102            namespaceRegistry.registerNamespace(RDF_PREFIX, SWORD_NAMESPACE);
103        } catch (RepositoryException e) {
104            throw new RuntimeException(
105                    String.format("Failed to register namespace %s:%s", RDF_PREFIX, SWORD_NAMESPACE), e);
106        }
107    }
108
109    private Container getContainer(final Session session, final String path, final String label) {
110        try {
111            if (!nodeService.exists(session, path)) {
112                log.info("Initializing container `{}` at `{}`", label, path);
113                final Container c = containerService.findOrCreate(session, path);
114                session.save();
115                return c;
116            }
117        } catch (RepositoryException e) {
118            throw new RuntimeException("Failed to initialize container " + label, e);
119        }
120        return null;
121    }
122
123    private void ensureProperty(
124            final NamespaceRegistry namespaceRegistry,
125            final Container container,
126            final String name,
127            final Object defaultValue) {
128        try {
129            final Map<String, String> namespaceMapping = emptyMap();
130            final String propertyName = getPropertyNameFromPredicate(
131                    (org.modeshape.jcr.api.NamespaceRegistry) namespaceRegistry,
132                    createProperty(name),
133                    namespaceMapping);
134            if (!container.getNode().hasProperty(propertyName)) {
135                container.getNode().setProperty(propertyName, String.valueOf(defaultValue));
136            }
137        } catch (RepositoryException e) {
138            throw new RuntimeException("Failed to initialize property " + name, e);
139        }
140    }
141
142}