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