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