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.http.api; 017 018 019import static javax.ws.rs.core.MediaType.APPLICATION_XHTML_XML; 020import static javax.ws.rs.core.MediaType.APPLICATION_XML; 021import static javax.ws.rs.core.MediaType.TEXT_HTML; 022import static javax.ws.rs.core.MediaType.TEXT_PLAIN; 023import static javax.ws.rs.core.Response.noContent; 024import static org.fcrepo.http.commons.domain.RDFMediaType.JSON_LD; 025import static org.fcrepo.http.commons.domain.RDFMediaType.N3; 026import static org.fcrepo.http.commons.domain.RDFMediaType.N3_ALT2; 027import static org.fcrepo.http.commons.domain.RDFMediaType.NTRIPLES; 028import static org.fcrepo.http.commons.domain.RDFMediaType.RDF_XML; 029import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE; 030import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_X; 031import static org.fcrepo.kernel.FedoraJcrTypes.FCR_VERSIONS; 032import static org.slf4j.LoggerFactory.getLogger; 033 034import java.io.IOException; 035 036import javax.annotation.PostConstruct; 037import javax.inject.Inject; 038import javax.jcr.RepositoryException; 039import javax.jcr.Session; 040import javax.ws.rs.DELETE; 041import javax.ws.rs.GET; 042import javax.ws.rs.HeaderParam; 043import javax.ws.rs.Path; 044import javax.ws.rs.PathParam; 045import javax.ws.rs.Produces; 046import javax.ws.rs.core.Response; 047 048import org.fcrepo.http.commons.domain.PATCH; 049import org.fcrepo.kernel.models.FedoraBinary; 050import org.fcrepo.kernel.models.FedoraResource; 051import org.fcrepo.kernel.utils.iterators.RdfStream; 052import org.slf4j.Logger; 053import org.springframework.context.annotation.Scope; 054 055import com.google.common.annotations.VisibleForTesting; 056 057/** 058 * Endpoint for managing versions of nodes 059 * 060 * @author awoods 061 * @author ajs6f 062 */ 063@Scope("request") 064@Path("/{path: .*}/fcr:versions/{labelAndOptionalPathIntoVersion: .*}") 065public class FedoraVersions extends ContentExposingResource { 066 067 @Inject 068 protected Session session; 069 070 private static final Logger LOGGER = getLogger(FedoraVersions.class); 071 072 @PathParam("path") protected String externalPath; 073 074 @PathParam("labelAndOptionalPathIntoVersion") protected String pathListIntoVersion; 075 076 protected String path; 077 protected String label; 078 protected String pathIntoVersion; 079 080 protected FedoraResource resource; 081 protected FedoraResource baseResource; 082 083 /** 084 * Default JAX-RS entry point 085 */ 086 public FedoraVersions() { 087 super(); 088 } 089 090 /** 091 * Create a new FedoraNodes instance for a given path 092 * @param path the path 093 * @param label the label 094 * @param pathIntoVersion the string value of pathIntoVersion 095 */ 096 @VisibleForTesting 097 public FedoraVersions(final String path, final String label, final String pathIntoVersion) { 098 this.path = path; 099 this.label = label; 100 this.pathIntoVersion = pathIntoVersion; 101 } 102 103 @PostConstruct 104 private void postConstruct() { 105 this.path = externalPath + "/" + FCR_VERSIONS + "/" + pathListIntoVersion; 106 this.label = pathListIntoVersion.split("/", 2)[0]; 107 } 108 109 /** 110 * Reverts the resource at the given path to the version specified by 111 * the label. 112 * @return response 113 * @throws RepositoryException if repository exception occurred 114 */ 115 @PATCH 116 public Response revertToVersion() throws RepositoryException { 117 LOGGER.info("Reverting {} to version {}.", path, 118 label); 119 versionService.revertToVersion(session, unversionedResourcePath(), label); 120 return noContent().build(); 121 } 122 123 /** 124 * Removes the version specified by the label. 125 * @return 204 No Content 126 * @throws RepositoryException if repository exception occurred 127 **/ 128 @DELETE 129 public Response removeVersion() throws RepositoryException { 130 LOGGER.info("Removing {} version {}.", path, label); 131 versionService.removeVersion(session, unversionedResourcePath(), label); 132 return noContent().build(); 133 } 134 135 /** 136 * Retrieve a version of an object. The path structure is as follows 137 * (though these URLs are returned from getVersionList and need not be 138 * constructed manually): 139 * /versionable-node/fcr:versions/label/path/to/any/copied/unversionable/nodes 140 * @param rangeValue the range value 141 * @throws IOException if IO exception occurred 142 * @return the version of the object as RDF in the requested format 143 */ 144 @GET 145 @Produces({TURTLE + ";qs=10", JSON_LD + ";qs=8", 146 N3, N3_ALT2, RDF_XML, NTRIPLES, APPLICATION_XML, TEXT_PLAIN, TURTLE_X, 147 TEXT_HTML, APPLICATION_XHTML_XML, "*/*"}) 148 public Response getVersion(@HeaderParam("Range") final String rangeValue) throws IOException { 149 LOGGER.trace("Getting version profile for: {} at version: {}", path, 150 label); 151 checkCacheControlHeaders(request, servletResponse, resource(), session); 152 final RdfStream rdfStream = new RdfStream().session(session).topic( 153 translator().reverse().convert(resource()).asNode()); 154 return getContent(rangeValue, rdfStream); 155 } 156 157 protected String unversionedResourcePath() { 158 159 if (baseResource == null) { 160 baseResource = getResourceFromPath(externalPath); 161 if ( baseResource instanceof FedoraBinary ) { 162 baseResource = ((FedoraBinary)baseResource).getDescription(); 163 } 164 } 165 166 return baseResource.getPath(); 167 } 168 169 @Override 170 protected FedoraResource resource() { 171 172 if (resource == null) { 173 resource = getResourceFromPath(path); 174 } 175 176 return resource; 177 } 178 179 @Override 180 protected void addResourceHttpHeaders(final FedoraResource resource) { 181 // no-op 182 } 183 184 @Override 185 protected String externalPath() { 186 return externalPath; 187 } 188 189 190 @Override 191 protected Session session() { 192 return session; 193 } 194}