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.Status.BAD_REQUEST; 021import static javax.ws.rs.core.Response.created; 022import static javax.ws.rs.core.Response.noContent; 023import static javax.ws.rs.core.Response.status; 024import static org.apache.commons.lang3.StringUtils.isBlank; 025import static org.fcrepo.kernel.api.RequiredRdfContext.VERSIONS; 026import static org.fcrepo.http.commons.domain.RDFMediaType.JSON_LD; 027import static org.fcrepo.http.commons.domain.RDFMediaType.N3_WITH_CHARSET; 028import static org.fcrepo.http.commons.domain.RDFMediaType.N3_ALT2_WITH_CHARSET; 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.TEXT_HTML_WITH_CHARSET; 032import static org.fcrepo.http.commons.domain.RDFMediaType.TEXT_PLAIN_WITH_CHARSET; 033import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_WITH_CHARSET; 034import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_X; 035import static org.slf4j.LoggerFactory.getLogger; 036 037import java.net.URI; 038 039import javax.jcr.RepositoryException; 040import javax.servlet.http.HttpServletResponse; 041import javax.ws.rs.DELETE; 042import javax.ws.rs.GET; 043import javax.ws.rs.HeaderParam; 044import javax.ws.rs.POST; 045import javax.ws.rs.PUT; 046import javax.ws.rs.Path; 047import javax.ws.rs.PathParam; 048import javax.ws.rs.Produces; 049import javax.ws.rs.core.Context; 050import javax.ws.rs.core.Request; 051import javax.ws.rs.core.Response; 052import javax.ws.rs.core.UriInfo; 053 054import org.fcrepo.http.commons.responses.HtmlTemplate; 055import org.fcrepo.http.commons.responses.RdfNamespacedStream; 056import org.fcrepo.kernel.api.exception.RepositoryVersionRuntimeException; 057import org.fcrepo.kernel.api.models.FedoraResource; 058import org.fcrepo.kernel.api.rdf.DefaultRdfStream; 059import org.slf4j.Logger; 060import org.springframework.context.annotation.Scope; 061 062import com.google.common.annotations.VisibleForTesting; 063 064/** 065 * @author cabeer 066 * @since 9/25/14 067 */ 068@Scope("request") 069@Path("/{path: .*}/fcr:versions") 070public class FedoraVersioning extends FedoraBaseResource { 071 072 private static final Logger LOGGER = getLogger(FedoraVersioning.class); 073 074 075 @Context protected Request request; 076 @Context protected HttpServletResponse servletResponse; 077 @Context protected UriInfo uriInfo; 078 079 @PathParam("path") protected String externalPath; 080 081 protected FedoraResource resource; 082 083 084 /** 085 * Default JAX-RS entry point 086 */ 087 public FedoraVersioning() { 088 super(); 089 } 090 091 /** 092 * Create a new FedoraNodes instance for a given path 093 * @param externalPath the external path 094 */ 095 @VisibleForTesting 096 public FedoraVersioning(final String externalPath) { 097 this.externalPath = externalPath; 098 } 099 100 101 /** 102 * Enable versioning 103 * @return the response 104 */ 105 @PUT 106 public Response enableVersioning() { 107 LOGGER.info("Enable versioning for '{}'", externalPath); 108 resource().enableVersioning(); 109 session.commit(); 110 return created(uriInfo.getRequestUri()).build(); 111 } 112 113 /** 114 * Disable versioning 115 * @return the response 116 */ 117 @DELETE 118 public Response disableVersioning() { 119 LOGGER.info("Disable versioning for '{}'", externalPath); 120 resource().disableVersioning(); 121 session.commit(); 122 return noContent().build(); 123 } 124 125 /** 126 * Create a new version checkpoint and tag it with the given label. If 127 * that label already describes another version it will silently be 128 * reassigned to describe this version. 129 * 130 * @param slug the value of slug 131 * @throws RepositoryException the exception 132 * @return response 133 */ 134 @POST 135 public Response addVersion(@HeaderParam("Slug") final String slug) throws RepositoryException { 136 if (!isBlank(slug)) { 137 LOGGER.info("Request to add version '{}' for '{}'", slug, externalPath); 138 final String path = toPath(translator(), externalPath); 139 versionService.createVersion(session.getFedoraSession(), path, slug); 140 return created(URI.create(translator().reverse().convert(resource().getBaseVersion()).getURI())).build(); 141 } 142 return status(BAD_REQUEST).entity("Specify label for version").build(); 143 } 144 145 146 /** 147 * Get the list of versions for the object 148 * 149 * @return List of versions for the object as RDF 150 */ 151 @SuppressWarnings("resource") 152 @GET 153 @HtmlTemplate(value = "fcr:versions") 154 @Produces({TURTLE_WITH_CHARSET + ";qs=1.0", JSON_LD + ";qs=0.8", N3_WITH_CHARSET, N3_ALT2_WITH_CHARSET, 155 RDF_XML, NTRIPLES, TEXT_PLAIN_WITH_CHARSET, 156 TURTLE_X, TEXT_HTML_WITH_CHARSET, "*/*"}) 157 public RdfNamespacedStream getVersionList() { 158 if (!resource().isVersioned()) { 159 throw new RepositoryVersionRuntimeException("This operation requires that the node be versionable"); 160 } 161 162 return new RdfNamespacedStream(new DefaultRdfStream( 163 asNode(resource()), 164 resource().getTriples(translator(), VERSIONS)), 165 session().getFedoraSession().getNamespaces()); 166 } 167 168 protected FedoraResource resource() { 169 if (resource == null) { 170 resource = getResourceFromPath(externalPath); 171 } 172 173 return resource; 174 } 175 176}