/* * Licensed to DuraSpace under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * DuraSpace licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fcrepo.kernel.modeshape.rdf.impl; import static com.google.common.collect.Lists.newArrayList; import static org.apache.jena.rdf.model.ResourceFactory.createResource; import com.google.common.base.Converter; import com.google.common.collect.Lists; import org.fcrepo.kernel.api.models.FedoraResource; import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; import org.fcrepo.kernel.api.identifiers.IdentifierConverter; import org.apache.jena.rdf.model.Resource; import org.fcrepo.kernel.modeshape.identifiers.HashConverter; import org.fcrepo.kernel.modeshape.identifiers.NamespaceConverter; import org.fcrepo.kernel.modeshape.identifiers.NodeResourceConverter; import javax.jcr.RepositoryException; import javax.jcr.Session; import java.util.List; /** * A very simple {@link IdentifierConverter} which translates JCR paths into Fedora subjects with * a configurable resource namespace (e.g., a baseURL). When a REST API context is available for * constructing URIs, org.fcrepo.http.commons.api.rdf.HttpResourceConverter should be used instead. * * @author barmintor * @author ajs6f * @author escowles * @since 2015-04-24 */ public class PrefixingIdentifierTranslator extends IdentifierConverter<Resource, FedoraResource> { private static final NodeResourceConverter nodeResourceConverter = new NodeResourceConverter(); private final String resourceNamespace; private final Session session; /** * Construct the graph with the provided resource namespace, which will translate JCR paths into * URIs prefixed with that namespace. Should only be used when a REST API context is not available * for constructing URIs. * @param session Session to lookup nodes * @param resourceNamespace Resource namespace (i.e., base URL) **/ public PrefixingIdentifierTranslator(final Session session, final String resourceNamespace) { this.session = session; this.resourceNamespace = resourceNamespace; setTranslationChain(); } protected Converter<String, String> forward = identity(); protected Converter<String, String> reverse = identity(); /* * TODO: much of what happens with chains of translators inside these converters should be factored * out into some abstract class, or post Java 8, default implementation. */ private void setTranslationChain() { for (final Converter<String, String> t : minimalTranslationChain) { forward = forward.andThen(t); } for (final Converter<String, String> t : Lists.reverse(minimalTranslationChain)) { reverse = reverse.andThen(t.reverse()); } } @SuppressWarnings("unchecked") private static final List<Converter<String, String>> minimalTranslationChain = newArrayList((Converter<String, String>) new NamespaceConverter(), (Converter<String, String>) new HashConverter() ); @Override protected FedoraResource doForward(final Resource subject) { try { if (!inDomain(subject)) { throw new RepositoryRuntimeException("Subject " + subject + " is not in this repository"); } return nodeResourceConverter.convert(session.getNode(asString(subject))); } catch (final RepositoryException e) { throw new RepositoryRuntimeException(e); } } @Override protected Resource doBackward(final FedoraResource resource) { final String absPath = resource.getPath(); return toDomain(absPath); } @Override public boolean inDomain(final Resource subject) { return subject.isURIResource() && subject.getURI().startsWith(resourceNamespace); } @Override public Resource toDomain(final String absPath) { final String relativePath; if (absPath.startsWith("/")) { relativePath = absPath.substring(1); } else { relativePath = absPath; } return createResource(resourceNamespace + reverse.convert(relativePath)); } @Override public String asString(final Resource subject) { if (!inDomain(subject)) { return null; } final String path = subject.getURI().substring(resourceNamespace.length() - 1); final String absPath = forward.convert(path); if (absPath.isEmpty()) { return "/"; } return absPath; } }