001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.kernel.modeshape.services;
019
020import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_CONTAINER;
021import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_RESOURCE;
022import static org.fcrepo.kernel.api.FedoraTypes.LDP_BASIC_CONTAINER;
023import static org.fcrepo.kernel.api.FedoraTypes.LDP_DIRECT_CONTAINER;
024import static org.fcrepo.kernel.api.FedoraTypes.LDP_HAS_MEMBER_RELATION;
025import static org.fcrepo.kernel.api.FedoraTypes.LDP_INDIRECT_CONTAINER;
026import static org.fcrepo.kernel.api.FedoraTypes.LDP_INSERTED_CONTENT_RELATION;
027import static org.fcrepo.kernel.api.FedoraTypes.LDP_MEMBER_RESOURCE;
028import static org.fcrepo.kernel.api.RdfLexicon.LDP_MEMBER;
029import static org.fcrepo.kernel.api.RdfLexicon.MEMBER_SUBJECT;
030import static org.fcrepo.kernel.modeshape.ContainerImpl.hasMixin;
031import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getContainingNode;
032import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touch;
033import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touchLdpMembershipResource;
034import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
035import static org.modeshape.jcr.api.JcrConstants.NT_FOLDER;
036import static org.slf4j.LoggerFactory.getLogger;
037
038import javax.jcr.Node;
039import javax.jcr.RepositoryException;
040
041import org.fcrepo.kernel.api.FedoraSession;
042import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
043import org.fcrepo.kernel.api.exception.ResourceTypeException;
044import org.fcrepo.kernel.api.models.Container;
045import org.fcrepo.kernel.api.services.ContainerService;
046import org.fcrepo.kernel.modeshape.ContainerImpl;
047
048import org.slf4j.Logger;
049import org.springframework.stereotype.Component;
050
051/**
052 * Service for creating and retrieving {@link org.fcrepo.kernel.api.models.Container} without using the JCR API.
053 *
054 * @author cbeer
055 * @author ajs6f
056 * @since Feb 11, 2013
057 */
058@Component
059public class ContainerServiceImpl extends AbstractService implements ContainerService {
060
061    private static final Logger LOGGER = getLogger(ContainerServiceImpl.class);
062
063    @Override
064    public Container findOrCreate(final FedoraSession session, final String path, final String interactionModel) {
065        LOGGER.trace("Executing findOrCreateObject() with path: {}", path);
066
067        try {
068            final Node node = findOrCreateNode(session, path, NT_FOLDER);
069
070            if (node.isNew()) {
071                initializeNewObjectProperties(node);
072
073                getContainingNode(node).ifPresent(parent -> {
074                    touch(parent);
075                    touchLdpMembershipResource(node);
076                });
077
078                if (LDP_INDIRECT_CONTAINER.equals(interactionModel)) {
079                    node.addMixin(LDP_INDIRECT_CONTAINER);
080                    node.setProperty(LDP_MEMBER_RESOURCE, node);
081                    node.setProperty(LDP_HAS_MEMBER_RELATION, LDP_MEMBER.getURI());
082                    node.setProperty(LDP_INSERTED_CONTENT_RELATION, MEMBER_SUBJECT.getURI());
083                } else if (LDP_DIRECT_CONTAINER.equals(interactionModel)) {
084                    node.addMixin(LDP_DIRECT_CONTAINER);
085                    node.setProperty(LDP_MEMBER_RESOURCE, node);
086                    node.setProperty(LDP_HAS_MEMBER_RELATION, LDP_MEMBER.getURI());
087                } else {
088                    node.addMixin(LDP_BASIC_CONTAINER);
089                }
090            }
091
092            if (node.isNew()) {
093                touch(node);
094            }
095
096            return new ContainerImpl(node);
097        } catch (final RepositoryException e) {
098            throw new RepositoryRuntimeException(e);
099        }
100    }
101
102    /**
103     * @param path the path
104     * @param session the session
105     * @return A {@link org.fcrepo.kernel.api.models.Container} with the proffered PID
106     */
107    @Override
108    public Container findOrCreate(final FedoraSession session, final String path) {
109        return findOrCreate(session, path, null);
110    }
111
112    /**
113     * Retrieve a {@link org.fcrepo.kernel.api.models.Container} instance by pid and dsid
114     *
115     * @param path the path
116     * @param session the session
117     * @return A {@link org.fcrepo.kernel.api.models.Container} with the proffered PID
118     */
119    @Override
120    public Container find(final FedoraSession session, final String path) {
121        final Node node = findNode(session, path);
122
123        return cast(node);
124    }
125
126    private static void initializeNewObjectProperties(final Node node) {
127        try {
128            LOGGER.debug("Setting object properties on node {}...", node.getPath());
129
130            if (node.canAddMixin(FEDORA_RESOURCE)) {
131                node.addMixin(FEDORA_RESOURCE);
132            }
133
134            if (node.canAddMixin(FEDORA_CONTAINER)) {
135                node.addMixin(FEDORA_CONTAINER);
136            }
137
138        } catch (final RepositoryException e) {
139            LOGGER.warn("Could not decorate {} with {} properties: {} ",
140                    JCR_CONTENT, FEDORA_CONTAINER, e);
141        }
142    }
143
144    private Container cast(final Node node) {
145        assertIsType(node);
146        return new ContainerImpl(node);
147    }
148
149    private static void assertIsType(final Node node) {
150        if (!hasMixin(node)) {
151            throw new ResourceTypeException(node + " can not be used as a object");
152        }
153    }
154
155}