001/* 002 * Copyright 2015 DuraSpace, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.fcrepo.http.api; 017 018import static javax.ws.rs.core.Response.created; 019import static javax.ws.rs.core.Response.noContent; 020import static javax.ws.rs.core.Response.status; 021import static javax.ws.rs.core.Response.Status.BAD_REQUEST; 022import static org.slf4j.LoggerFactory.getLogger; 023 024import java.net.URI; 025import java.net.URISyntaxException; 026import java.security.Principal; 027 028import javax.servlet.http.HttpServletRequest; 029import javax.ws.rs.POST; 030import javax.ws.rs.Path; 031import javax.ws.rs.PathParam; 032import javax.ws.rs.core.Context; 033import javax.ws.rs.core.Response; 034 035import org.fcrepo.kernel.api.Transaction; 036import org.fcrepo.kernel.api.TxSession; 037import org.fcrepo.kernel.api.services.TransactionService; 038import org.slf4j.Logger; 039import org.springframework.beans.factory.annotation.Autowired; 040import org.springframework.context.annotation.Scope; 041 042/** 043 * Transactions over REST 044 * 045 * @author awoods 046 * @author gregjan 047 */ 048@Scope("prototype") 049@Path("/{path: .*}/fcr:tx") 050public class FedoraTransactions extends FedoraBaseResource { 051 052 private static final Logger LOGGER = getLogger(FedoraTransactions.class); 053 054 @Autowired 055 private TransactionService txService; 056 057 /** 058 * Create a new transaction resource and add it to the registry 059 * 060 * @param externalPath the external path 061 * @param req the http servlet request 062 * @return 201 with the transaction id and expiration date 063 * @throws URISyntaxException if URI syntax exception occurred 064 */ 065 @POST 066 public Response createTransaction(@PathParam("path") final String externalPath, 067 @Context final HttpServletRequest req) throws URISyntaxException { 068 069 if (session instanceof TxSession) { 070 final Transaction t = txService.getTransaction(session); 071 LOGGER.debug("renewing transaction {}", t.getId()); 072 t.updateExpiryDate(); 073 return noContent().expires(t.getExpires()).build(); 074 } 075 076 if (externalPath != null && !externalPath.isEmpty()) { 077 return status(BAD_REQUEST).build(); 078 } 079 080 final Principal userPrincipal = req.getUserPrincipal(); 081 String userName = null; 082 if (userPrincipal != null) { 083 userName = userPrincipal.getName(); 084 } 085 086 final Transaction t = txService.beginTransaction(session, userName); 087 LOGGER.info("Created transaction '{}'", t.getId()); 088 089 return created(new URI(translator().toDomain("/tx:" + t.getId()).toString())).expires( 090 t.getExpires()).build(); 091 } 092 093 /** 094 * Commit a transaction resource 095 * 096 * @param externalPath the external path 097 * @return 204 098 */ 099 @POST 100 @Path("fcr:commit") 101 public Response commit(@PathParam("path") final String externalPath) { 102 LOGGER.info("Commit transaction '{}'", externalPath); 103 return finalizeTransaction(externalPath, true); 104 105 } 106 107 /** 108 * Rollback a transaction 109 * 110 * @param externalPath the external path 111 * @return 204 112 */ 113 @POST 114 @Path("fcr:rollback") 115 public Response rollback(@PathParam("path") final String externalPath) { 116 LOGGER.info("Rollback transaction '{}'", externalPath); 117 return finalizeTransaction(externalPath, false); 118 } 119 120 private Response finalizeTransaction(@PathParam("path") 121 final String externalPath, final boolean commit) { 122 123 final String path = toPath(translator(), externalPath); 124 if (!path.equals("/")) { 125 return status(BAD_REQUEST).build(); 126 } 127 128 final String txId; 129 if (session instanceof TxSession) { 130 txId = ((TxSession) session).getTxId(); 131 } else { 132 txId = ""; 133 } 134 135 if (txId.isEmpty()) { 136 LOGGER.debug("cannot finalize an empty tx id {} at path {}", 137 txId, path); 138 return status(BAD_REQUEST).build(); 139 } 140 141 if (commit) { 142 LOGGER.debug("commiting transaction {} at path {}", txId, path); 143 txService.commit(txId); 144 145 } else { 146 LOGGER.debug("rolling back transaction {} at path {}", txId, 147 path); 148 txService.rollback(txId); 149 } 150 return noContent().build(); 151 } 152}