001/** 002 * Copyright 2015 DuraSpace, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.fcrepo.kernel.impl.rdf.impl; 017 018import static com.google.common.collect.Lists.newArrayList; 019import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource; 020 021import com.google.common.base.Converter; 022import com.google.common.collect.Lists; 023 024import org.fcrepo.kernel.models.FedoraResource; 025import org.fcrepo.kernel.exception.RepositoryRuntimeException; 026import org.fcrepo.kernel.identifiers.IdentifierConverter; 027 028import com.hp.hpl.jena.rdf.model.Resource; 029 030import org.fcrepo.kernel.impl.identifiers.HashConverter; 031import org.fcrepo.kernel.impl.identifiers.NamespaceConverter; 032import org.fcrepo.kernel.impl.identifiers.NodeResourceConverter; 033 034import javax.jcr.RepositoryException; 035import javax.jcr.Session; 036 037import java.util.List; 038 039/** 040 * A very simple {@link IdentifierConverter} which translates JCR paths into Fedora subjects with 041 * a configurable resource namespace (e.g., a baseURL). When a REST API context is available for 042 * constructing URIs, org.fcrepo.http.commons.api.rdf.HttpResourceConverter should be used instead. 043 * 044 * @author barmintor 045 * @author ajs6f 046 * @author escowles 047 * @since 2015-04-24 048 */ 049public class PrefixingIdentifierTranslator extends IdentifierConverter<Resource, FedoraResource> { 050 051 052 private static final NodeResourceConverter nodeResourceConverter = new NodeResourceConverter(); 053 054 private final String resourceNamespace; 055 private final Session session; 056 057 /** 058 * Construct the graph with the provided resource namespace, which will translate JCR paths into 059 * URIs prefixed with that namespace. Should only be used when a REST API context is not available 060 * for constructing URIs. 061 * @param session Session to lookup nodes 062 * @param resourceNamespace Resource namespace (i.e., base URL) 063 **/ 064 public PrefixingIdentifierTranslator(final Session session, final String resourceNamespace) { 065 this.session = session; 066 this.resourceNamespace = resourceNamespace; 067 setTranslationChain(); 068 } 069 070 071 protected Converter<String, String> forward = identity(); 072 protected Converter<String, String> reverse = identity(); 073 074 /* 075 * TODO: much of what happens with chains of translators inside these converters should be factored 076 * out into some abstract class, or post Java 8, default implementation. 077 */ 078 private void setTranslationChain() { 079 080 for (final Converter<String, String> t : minimalTranslationChain) { 081 forward = forward.andThen(t); 082 } 083 for (final Converter<String, String> t : Lists.reverse(minimalTranslationChain)) { 084 reverse = reverse.andThen(t.reverse()); 085 } 086 } 087 088 089 @SuppressWarnings("unchecked") 090 private static final List<Converter<String, String>> minimalTranslationChain = 091 newArrayList((Converter<String, String>) new NamespaceConverter(), 092 (Converter<String, String>) new HashConverter() 093 ); 094 095 @Override 096 protected FedoraResource doForward(final Resource subject) { 097 try { 098 if (!inDomain(subject)) { 099 throw new RepositoryRuntimeException("Subject " + subject + " is not in this repository"); 100 } 101 102 return nodeResourceConverter.convert(session.getNode(asString(subject))); 103 } catch (final RepositoryException e) { 104 throw new RepositoryRuntimeException(e); 105 } 106 } 107 108 @Override 109 protected Resource doBackward(final FedoraResource resource) { 110 final String absPath = resource.getPath(); 111 112 return toDomain(absPath); 113 } 114 115 @Override 116 public boolean inDomain(final Resource subject) { 117 return subject.isURIResource() && subject.getURI().startsWith(resourceNamespace); 118 } 119 120 @Override 121 public Resource toDomain(final String absPath) { 122 final String relativePath; 123 124 if (absPath.startsWith("/")) { 125 relativePath = absPath.substring(1); 126 } else { 127 relativePath = absPath; 128 } 129 return createResource(resourceNamespace + reverse.convert(relativePath)); 130 } 131 132 @Override 133 public String asString(final Resource subject) { 134 if (!inDomain(subject)) { 135 return null; 136 } 137 138 final String path = subject.getURI().substring(resourceNamespace.length() - 1); 139 140 final String absPath = forward.convert(path); 141 142 if (absPath.isEmpty()) { 143 return "/"; 144 } 145 return absPath; 146 } 147 148}