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