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