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_GATEWAY; 021import static javax.ws.rs.core.Response.Status.CONFLICT; 022import static javax.ws.rs.core.Response.Status.PRECONDITION_FAILED; 023import static javax.ws.rs.core.Response.created; 024import static org.slf4j.LoggerFactory.getLogger; 025 026import java.net.URI; 027import java.net.URISyntaxException; 028 029import javax.annotation.PostConstruct; 030import javax.jcr.ItemExistsException; 031import javax.jcr.PathNotFoundException; 032import javax.servlet.http.HttpServletResponse; 033import javax.ws.rs.ClientErrorException; 034import javax.ws.rs.HeaderParam; 035import javax.ws.rs.Path; 036import javax.ws.rs.PathParam; 037import javax.ws.rs.ServerErrorException; 038import javax.ws.rs.core.Context; 039import javax.ws.rs.core.Request; 040import javax.ws.rs.core.Response; 041import javax.ws.rs.core.UriInfo; 042 043import org.fcrepo.http.commons.domain.COPY; 044import org.fcrepo.http.commons.domain.MOVE; 045import org.fcrepo.kernel.api.models.FedoraResource; 046import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; 047import org.slf4j.Logger; 048import org.springframework.context.annotation.Scope; 049 050import com.codahale.metrics.annotation.Timed; 051import com.google.common.annotations.VisibleForTesting; 052import org.apache.jena.rdf.model.ResourceFactory; 053 054/** 055 * CRUD operations on Fedora Nodes 056 * 057 * @author cbeer 058 */ 059@Scope("request") 060@Path("/{path: .*}") 061public class FedoraNodes extends ContentExposingResource { 062 063 private static final Logger LOGGER = getLogger(FedoraNodes.class); 064 065 @Context protected Request request; 066 @Context protected HttpServletResponse servletResponse; 067 @Context protected UriInfo uriInfo; 068 069 @PathParam("path") protected String externalPath; 070 071 protected FedoraResource resource; 072 073 /** 074 * Default JAX-RS entry point 075 */ 076 public FedoraNodes() { 077 super(); 078 } 079 080 /** 081 * Create a new FedoraNodes instance for a given path 082 * @param externalPath the external path 083 */ 084 @VisibleForTesting 085 public FedoraNodes(final String externalPath) { 086 this.externalPath = externalPath; 087 } 088 089 090 /** 091 * Run these actions after initializing this resource 092 */ 093 @PostConstruct 094 public void postConstruct() { 095 setUpJMSInfo(uriInfo, headers); 096 } 097 098 /** 099 * Copies an object from one path to another 100 * @param destinationUri the destination uri 101 * @throws URISyntaxException if uri syntax exception occurred 102 * @return the response 103 */ 104 @COPY 105 @Timed 106 public Response copyObject(@HeaderParam("Destination") final String destinationUri) 107 throws URISyntaxException { 108 109 try { 110 final String source = translator().asString(translator().toDomain(externalPath)); 111 112 if (!nodeService.exists(session.getFedoraSession(), source)) { 113 throw new ClientErrorException("The source path does not exist", CONFLICT); 114 } 115 116 final String destination = translator().asString(ResourceFactory.createResource(destinationUri)); 117 118 if (destination == null) { 119 throw new ServerErrorException("Destination was not a valid resource path", BAD_GATEWAY); 120 } else if (nodeService.exists(session.getFedoraSession(), destination)) { 121 throw new ClientErrorException("Destination resource already exists", PRECONDITION_FAILED); 122 } 123 124 LOGGER.info("Copy from '{}' to '{}'", source, destination); 125 nodeService.copyObject(session.getFedoraSession(), source, destination); 126 session.commit(); 127 128 return created(new URI(destinationUri)).build(); 129 } catch (final RepositoryRuntimeException e) { 130 final Throwable cause = e.getCause(); 131 132 if (cause instanceof ItemExistsException) { 133 134 throw new ClientErrorException("Destination resource already exists", PRECONDITION_FAILED, e); 135 136 } else if (cause instanceof PathNotFoundException) { 137 138 throw new ClientErrorException("There is no node that will serve as the parent of the copied item", 139 CONFLICT, e); 140 } else { 141 throw e; 142 } 143 } 144 145 } 146 147 /** 148 * Copies an object from one path to another 149 * @param destinationUri the destination uri 150 * @throws URISyntaxException if uri syntax exception occurred 151 * @return the response 152 */ 153 @MOVE 154 @Timed 155 public Response moveObject(@HeaderParam("Destination") final String destinationUri) 156 throws URISyntaxException { 157 158 try { 159 160 final String source = toPath(translator(), externalPath); 161 162 if (!nodeService.exists(session.getFedoraSession(), source)) { 163 throw new ClientErrorException("The source path does not exist", CONFLICT); 164 } 165 166 167 evaluateRequestPreconditions(request, servletResponse, resource(), session); 168 169 final String destination = translator().asString(ResourceFactory.createResource(destinationUri)); 170 171 if (destination == null) { 172 throw new ServerErrorException("Destination was not a valid resource path", BAD_GATEWAY); 173 } else if (nodeService.exists(session.getFedoraSession(), destination)) { 174 throw new ClientErrorException("Destination resource already exists", PRECONDITION_FAILED); 175 } 176 177 LOGGER.info("Move from '{}' to '{}'", source, destination); 178 nodeService.moveObject(session.getFedoraSession(), source, destination); 179 session.commit(); 180 return created(new URI(destinationUri)).build(); 181 } catch (final RepositoryRuntimeException e) { 182 final Throwable cause = e.getCause(); 183 184 if (cause instanceof ItemExistsException) { 185 throw new ClientErrorException("Destination resource already exists", PRECONDITION_FAILED, e); 186 } else if (cause instanceof PathNotFoundException) { 187 throw new ClientErrorException("There is no node that will serve as the parent of the moved item", 188 CONFLICT, e); 189 } else { 190 throw e; 191 } 192 } 193 } 194 195 @Override 196 protected void addResourceHttpHeaders(final FedoraResource resource) { 197 throw new UnsupportedOperationException(); 198 } 199 200 @Override 201 protected String externalPath() { 202 return externalPath; 203 } 204 205}