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