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