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.models.NonRdfSourceDescription;
025import org.fcrepo.kernel.api.services.BinaryService;
026import org.fcrepo.kernel.modeshape.FedoraBinaryImpl;
027import org.fcrepo.kernel.modeshape.NonRdfSourceDescriptionImpl;
028import org.slf4j.Logger;
029import org.springframework.stereotype.Component;
030
031import javax.jcr.Node;
032import javax.jcr.RepositoryException;
033
034import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_BINARY;
035import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_NON_RDF_SOURCE_DESCRIPTION;
036import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_RESOURCE;
037import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_DESCRIPTION;
038import static org.fcrepo.kernel.api.RdfLexicon.NT_LEAF_NODE;
039import static org.fcrepo.kernel.api.RdfLexicon.NT_VERSION_FILE;
040import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getContainingNode;
041import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getJcrNode;
042import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touch;
043import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.touchLdpMembershipResource;
044import static org.slf4j.LoggerFactory.getLogger;
045
046/**
047 * @author cabeer
048 * @author ajs6f
049 * @since 10/10/14
050 */
051@Component
052public class BinaryServiceImpl extends AbstractService implements BinaryService {
053
054    private static final Logger LOGGER = getLogger(BinaryServiceImpl.class);
055
056    /**
057     * {@inheritDoc}
058     */
059    @Override
060    public FedoraBinary findOrCreate(final FedoraSession session, final String path) {
061        try {
062            final FedoraBinary binary = findOrCreateBinary(session, path);
063
064            final Node dsNode = getJcrNode(binary);
065            if (dsNode.isNew()) {
066                final String descPath = dsNode.getPath() + "/" + FEDORA_DESCRIPTION;
067                findOrCreateDescription(session, descPath);
068            }
069
070            return binary;
071        } catch (final RepositoryException e) {
072            throw new RepositoryRuntimeException(e);
073        }
074    }
075
076    /**
077     * {@inheritDoc}
078     */
079    @Override
080    public FedoraBinary findOrCreateBinary(final FedoraSession session, final String path) {
081        try {
082            final Node dsNode = findOrCreateNode(session, path, NT_VERSION_FILE);
083
084            if (dsNode.isNew()) {
085                initializeNewBinaryProperties(dsNode);
086
087                getContainingNode(dsNode).ifPresent(parent -> {
088                    touch(parent);
089                    touchLdpMembershipResource(dsNode);
090                });
091            }
092
093            final FedoraBinaryImpl binary = new FedoraBinaryImpl(dsNode);
094
095            if (dsNode.isNew()) {
096                touch(binary.getNode());
097            }
098
099            return binary;
100        } catch (final RepositoryException e) {
101            throw new RepositoryRuntimeException(e);
102        }
103    }
104
105    /**
106     * {@inheritDoc}
107     */
108    @Override
109    public NonRdfSourceDescription findOrCreateDescription(final FedoraSession session, final String path) {
110        try {
111            final Node descNode = findOrCreateNode(session, path, NT_LEAF_NODE);
112
113            initializeNewDescriptionProperties(descNode);
114
115            return new NonRdfSourceDescriptionImpl(descNode);
116        } catch (final RepositoryException e) {
117            throw new RepositoryRuntimeException(e);
118        }
119    }
120
121    /**
122     * Retrieve a Datastream instance by pid and dsid
123     *
124     * @param path jcr path to the datastream
125     * @return datastream
126     */
127    @Override
128    public FedoraBinary find(final FedoraSession session, final String path) {
129        return cast(findNode(session, path));
130    }
131
132    private static void initializeNewBinaryProperties(final Node node) {
133        try {
134
135            if (node.canAddMixin(FEDORA_RESOURCE)) {
136                node.addMixin(FEDORA_RESOURCE);
137            }
138            if (node.canAddMixin(FEDORA_BINARY)) {
139                node.addMixin(FEDORA_BINARY);
140            }
141        } catch (final RepositoryException e) {
142            LOGGER.warn("Could not decorate {} with binary properties: {}", node, e);
143        }
144    }
145
146    private static void initializeNewDescriptionProperties(final Node descNode) {
147        try {
148            if (descNode.canAddMixin(FEDORA_NON_RDF_SOURCE_DESCRIPTION)) {
149                descNode.addMixin(FEDORA_NON_RDF_SOURCE_DESCRIPTION);
150            }
151
152            if (descNode.canAddMixin(FEDORA_BINARY)) {
153                descNode.addMixin(FEDORA_BINARY);
154            }
155        } catch (final RepositoryException e) {
156            LOGGER.warn("Could not decorate {} with description properties: {}", descNode, e);
157        }
158    }
159
160    /**
161     * Retrieve a Datastream instance by pid and dsid
162     *
163     * @param node datastream node
164     * @return node as datastream
165     */
166    private FedoraBinary cast(final Node node) {
167        assertIsType(node);
168        return new FedoraBinaryImpl(node);
169    }
170
171    private static void assertIsType(final Node node) {
172        if (!FedoraBinaryImpl.hasMixin(node)) {
173            throw new ResourceTypeException(node + " can not be used as a binary");
174        }
175    }
176
177
178}