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.modeshape.ContainerImpl.hasMixin;
023import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getContainingNode;
024import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touch;
025import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touchLdpMembershipResource;
026import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
027import static org.modeshape.jcr.api.JcrConstants.NT_FOLDER;
028import static org.slf4j.LoggerFactory.getLogger;
029
030import javax.jcr.Node;
031import javax.jcr.RepositoryException;
032
033import org.fcrepo.kernel.api.FedoraSession;
034import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
035import org.fcrepo.kernel.api.exception.ResourceTypeException;
036import org.fcrepo.kernel.api.models.Container;
037import org.fcrepo.kernel.api.services.ContainerService;
038import org.fcrepo.kernel.modeshape.ContainerImpl;
039
040import org.slf4j.Logger;
041import org.springframework.stereotype.Component;
042
043/**
044 * Service for creating and retrieving {@link org.fcrepo.kernel.api.models.Container} without using the JCR API.
045 *
046 * @author cbeer
047 * @author ajs6f
048 * @since Feb 11, 2013
049 */
050@Component
051public class ContainerServiceImpl extends AbstractService implements ContainerService {
052
053    private static final Logger LOGGER = getLogger(ContainerServiceImpl.class);
054
055    /**
056     * @param path the path
057     * @param session the session
058     * @return A {@link org.fcrepo.kernel.api.models.Container} with the proffered PID
059     */
060    @Override
061    public Container findOrCreate(final FedoraSession session, final String path) {
062        LOGGER.trace("Executing findOrCreateObject() with path: {}", path);
063
064        try {
065            final Node node = findOrCreateNode(session, path, NT_FOLDER);
066
067            if (node.isNew()) {
068                initializeNewObjectProperties(node);
069
070                getContainingNode(node).ifPresent(parent -> {
071                    touch(parent);
072                    touchLdpMembershipResource(node);
073                });
074            }
075
076            if (node.isNew()) {
077                touch(node);
078            }
079
080            return new ContainerImpl(node);
081        } catch (final RepositoryException e) {
082            throw new RepositoryRuntimeException(e);
083        }
084    }
085
086    /**
087     * Retrieve a {@link org.fcrepo.kernel.api.models.Container} instance by pid and dsid
088     *
089     * @param path the path
090     * @param session the session
091     * @return A {@link org.fcrepo.kernel.api.models.Container} with the proffered PID
092     */
093    @Override
094    public Container find(final FedoraSession session, final String path) {
095        final Node node = findNode(session, path);
096
097        return cast(node);
098    }
099
100    private static void initializeNewObjectProperties(final Node node) {
101        try {
102            LOGGER.debug("Setting object properties on node {}...", node.getPath());
103
104            if (node.canAddMixin(FEDORA_RESOURCE)) {
105                node.addMixin(FEDORA_RESOURCE);
106            }
107
108            if (node.canAddMixin(FEDORA_CONTAINER)) {
109                node.addMixin(FEDORA_CONTAINER);
110            }
111
112        } catch (final RepositoryException e) {
113            LOGGER.warn("Could not decorate {} with {} properties: {} ",
114                    JCR_CONTENT, FEDORA_CONTAINER, e);
115        }
116    }
117
118    private Container cast(final Node node) {
119        assertIsType(node);
120        return new ContainerImpl(node);
121    }
122
123    private static void assertIsType(final Node node) {
124        if (!hasMixin(node)) {
125            throw new ResourceTypeException(node + " can not be used as a object");
126        }
127    }
128
129}