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.rdf.impl; 019 020import static com.google.common.collect.Lists.newArrayList; 021import static org.apache.jena.rdf.model.ResourceFactory.createResource; 022 023import com.google.common.base.Converter; 024import com.google.common.collect.Lists; 025 026import org.fcrepo.kernel.api.models.FedoraResource; 027import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; 028import org.fcrepo.kernel.api.identifiers.IdentifierConverter; 029 030import org.apache.jena.rdf.model.Resource; 031 032import org.fcrepo.kernel.modeshape.identifiers.HashConverter; 033import org.fcrepo.kernel.modeshape.identifiers.NamespaceConverter; 034import org.fcrepo.kernel.modeshape.identifiers.NodeResourceConverter; 035 036import javax.jcr.RepositoryException; 037import javax.jcr.Session; 038 039import java.util.List; 040 041/** 042 * A very simple {@link IdentifierConverter} which translates JCR paths into Fedora subjects with 043 * a configurable resource namespace (e.g., a baseURL). When a REST API context is available for 044 * constructing URIs, org.fcrepo.http.commons.api.rdf.HttpResourceConverter should be used instead. 045 * 046 * @author barmintor 047 * @author ajs6f 048 * @author escowles 049 * @since 2015-04-24 050 */ 051public class PrefixingIdentifierTranslator extends IdentifierConverter<Resource, FedoraResource> { 052 053 054 private static final NodeResourceConverter nodeResourceConverter = new NodeResourceConverter(); 055 056 private final String resourceNamespace; 057 private final Session session; 058 059 /** 060 * Construct the graph with the provided resource namespace, which will translate JCR paths into 061 * URIs prefixed with that namespace. Should only be used when a REST API context is not available 062 * for constructing URIs. 063 * @param session Session to lookup nodes 064 * @param resourceNamespace Resource namespace (i.e., base URL) 065 **/ 066 public PrefixingIdentifierTranslator(final Session session, final String resourceNamespace) { 067 this.session = session; 068 this.resourceNamespace = resourceNamespace; 069 setTranslationChain(); 070 } 071 072 073 protected Converter<String, String> forward = identity(); 074 protected Converter<String, String> reverse = identity(); 075 076 /* 077 * TODO: much of what happens with chains of translators inside these converters should be factored 078 * out into some abstract class, or post Java 8, default implementation. 079 */ 080 private void setTranslationChain() { 081 082 for (final Converter<String, String> t : minimalTranslationChain) { 083 forward = forward.andThen(t); 084 } 085 for (final Converter<String, String> t : Lists.reverse(minimalTranslationChain)) { 086 reverse = reverse.andThen(t.reverse()); 087 } 088 } 089 090 091 @SuppressWarnings("unchecked") 092 private static final List<Converter<String, String>> minimalTranslationChain = 093 newArrayList((Converter<String, String>) new NamespaceConverter(), 094 (Converter<String, String>) new HashConverter() 095 ); 096 097 @Override 098 protected FedoraResource doForward(final Resource subject) { 099 try { 100 if (!inDomain(subject)) { 101 throw new RepositoryRuntimeException("Subject " + subject + " is not in this repository"); 102 } 103 104 return nodeResourceConverter.convert(session.getNode(asString(subject))); 105 } catch (final RepositoryException e) { 106 throw new RepositoryRuntimeException(e); 107 } 108 } 109 110 @Override 111 protected Resource doBackward(final FedoraResource resource) { 112 final String absPath = resource.getPath(); 113 114 return toDomain(absPath); 115 } 116 117 @Override 118 public boolean inDomain(final Resource subject) { 119 return subject.isURIResource() && subject.getURI().startsWith(resourceNamespace); 120 } 121 122 @Override 123 public Resource toDomain(final String absPath) { 124 final String relativePath; 125 126 if (absPath.startsWith("/")) { 127 relativePath = absPath.substring(1); 128 } else { 129 relativePath = absPath; 130 } 131 return createResource(resourceNamespace + reverse.convert(relativePath)); 132 } 133 134 @Override 135 public String asString(final Resource subject) { 136 if (!inDomain(subject)) { 137 return null; 138 } 139 140 final String path = subject.getURI().substring(resourceNamespace.length() - 1); 141 142 final String absPath = forward.convert(path); 143 144 if (absPath.isEmpty()) { 145 return "/"; 146 } 147 return absPath; 148 } 149 150}