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 org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
021import org.fcrepo.kernel.api.exception.ResourceTypeException;
022import org.fcrepo.kernel.api.models.FedoraBinary;
023import org.fcrepo.kernel.api.services.BinaryService;
024import org.fcrepo.kernel.modeshape.FedoraBinaryImpl;
025import org.slf4j.Logger;
026import org.springframework.stereotype.Component;
027
028import javax.jcr.Node;
029import javax.jcr.RepositoryException;
030import javax.jcr.Session;
031
032import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_BINARY;
033import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_NON_RDF_SOURCE_DESCRIPTION;
034import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_RESOURCE;
035import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getContainingNode;
036import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touch;
037import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touchLdpMembershipResource;
038import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
039import static org.modeshape.jcr.api.JcrConstants.NT_FILE;
040import static org.modeshape.jcr.api.JcrConstants.NT_RESOURCE;
041import static org.slf4j.LoggerFactory.getLogger;
042
043/**
044 * @author cabeer
045 * @author ajs6f
046 * @since 10/10/14
047 */
048@Component
049public class BinaryServiceImpl extends AbstractService implements BinaryService {
050
051    private static final Logger LOGGER = getLogger(BinaryServiceImpl.class);
052
053    /**
054     * Retrieve or create a Datastream instance by pid and dsid
055     *
056     * @param path jcr path to the datastream
057     * @return datastream
058     */
059    @Override
060    public FedoraBinary findOrCreate(final Session session, final String path) {
061        try {
062            final Node dsNode = findOrCreateNode(session, path, NT_FILE);
063
064            if (dsNode.isNew()) {
065                initializeNewDatastreamProperties(dsNode);
066
067                getContainingNode(dsNode).ifPresent(parent -> {
068                    touch(parent);
069                    touchLdpMembershipResource(dsNode);
070                });
071            }
072
073            final FedoraBinaryImpl binary = new FedoraBinaryImpl(dsNode.getNode(JCR_CONTENT));
074
075            if (dsNode.isNew()) {
076                binary.touch();
077            }
078
079            return binary;
080        } catch (final RepositoryException e) {
081            throw new RepositoryRuntimeException(e);
082        }
083    }
084
085    /**
086     * Retrieve a Datastream instance by pid and dsid
087     *
088     * @param path jcr path to the datastream
089     * @return datastream
090     */
091    @Override
092    public FedoraBinary find(final Session session, final String path) {
093        try {
094            final Node dsNode = findNode(session, path);
095
096            return cast(dsNode.getNode(JCR_CONTENT));
097        } catch (final RepositoryException e) {
098            throw new RepositoryRuntimeException(e);
099        }
100    }
101
102    private static void initializeNewDatastreamProperties(final Node node) {
103        try {
104
105            if (node.canAddMixin(FEDORA_RESOURCE)) {
106                node.addMixin(FEDORA_RESOURCE);
107            }
108
109            if (node.canAddMixin(FEDORA_NON_RDF_SOURCE_DESCRIPTION)) {
110                node.addMixin(FEDORA_NON_RDF_SOURCE_DESCRIPTION);
111            }
112
113            final Node contentNode = jcrTools.findOrCreateChild(node, JCR_CONTENT, NT_RESOURCE);
114
115            if (contentNode.canAddMixin(FEDORA_BINARY)) {
116                contentNode.addMixin(FEDORA_BINARY);
117            }
118        } catch (final RepositoryException e) {
119            LOGGER.warn("Could not decorate {} with datastream properties: {}", node, e);
120        }
121
122    }
123    /**
124     * Retrieve a Datastream instance by pid and dsid
125     *
126     * @param node datastream node
127     * @return node as datastream
128     */
129    private FedoraBinary cast(final Node node) {
130        assertIsType(node);
131        return new FedoraBinaryImpl(node);
132    }
133
134    private static void assertIsType(final Node node) {
135        if (!FedoraBinaryImpl.hasMixin(node)) {
136            throw new ResourceTypeException(node + " can not be used as a binary");
137        }
138    }
139
140
141}