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.created; 021import static javax.ws.rs.core.Response.noContent; 022import static javax.ws.rs.core.Response.status; 023import static javax.ws.rs.core.Response.Status.BAD_REQUEST; 024import static org.slf4j.LoggerFactory.getLogger; 025 026import java.net.URI; 027import java.net.URISyntaxException; 028import java.security.Principal; 029 030import javax.inject.Inject; 031import javax.servlet.http.HttpServletRequest; 032import javax.ws.rs.POST; 033import javax.ws.rs.Path; 034import javax.ws.rs.PathParam; 035import javax.ws.rs.core.Context; 036import javax.ws.rs.core.Response; 037 038import org.fcrepo.kernel.api.Transaction; 039import org.fcrepo.kernel.api.TxSession; 040import org.fcrepo.kernel.api.services.TransactionService; 041import org.slf4j.Logger; 042import org.springframework.context.annotation.Scope; 043 044/** 045 * Transactions over REST 046 * 047 * @author awoods 048 * @author gregjan 049 */ 050@Scope("prototype") 051@Path("/{path: .*}/fcr:tx") 052public class FedoraTransactions extends FedoraBaseResource { 053 054 private static final Logger LOGGER = getLogger(FedoraTransactions.class); 055 056 @Inject 057 private TransactionService txService; 058 059 /** 060 * Create a new transaction resource and add it to the registry 061 * 062 * @param externalPath the external path 063 * @param req the http servlet request 064 * @return 201 with the transaction id and expiration date 065 * @throws URISyntaxException if URI syntax exception occurred 066 */ 067 @POST 068 public Response createTransaction(@PathParam("path") final String externalPath, 069 @Context final HttpServletRequest req) throws URISyntaxException { 070 071 if (session instanceof TxSession) { 072 final Transaction t = txService.getTransaction(session); 073 LOGGER.debug("renewing transaction {}", t.getId()); 074 t.updateExpiryDate(); 075 return noContent().expires(t.getExpires()).build(); 076 } 077 078 if (externalPath != null && !externalPath.isEmpty()) { 079 return status(BAD_REQUEST).build(); 080 } 081 082 final Principal userPrincipal = req.getUserPrincipal(); 083 String userName = null; 084 if (userPrincipal != null) { 085 userName = userPrincipal.getName(); 086 } 087 088 final Transaction t = txService.beginTransaction(session, userName); 089 LOGGER.info("Created transaction '{}'", t.getId()); 090 091 return created(new URI(translator().toDomain("/tx:" + t.getId()).toString())).expires( 092 t.getExpires()).build(); 093 } 094 095 /** 096 * Commit a transaction resource 097 * 098 * @param externalPath the external path 099 * @return 204 100 */ 101 @POST 102 @Path("fcr:commit") 103 public Response commit(@PathParam("path") final String externalPath) { 104 LOGGER.info("Commit transaction '{}'", externalPath); 105 return finalizeTransaction(externalPath, true); 106 107 } 108 109 /** 110 * Rollback a transaction 111 * 112 * @param externalPath the external path 113 * @return 204 114 */ 115 @POST 116 @Path("fcr:rollback") 117 public Response rollback(@PathParam("path") final String externalPath) { 118 LOGGER.info("Rollback transaction '{}'", externalPath); 119 return finalizeTransaction(externalPath, false); 120 } 121 122 private Response finalizeTransaction(@PathParam("path") 123 final String externalPath, final boolean commit) { 124 125 final String path = toPath(translator(), externalPath); 126 if (!path.equals("/")) { 127 return status(BAD_REQUEST).build(); 128 } 129 130 final String txId; 131 if (session instanceof TxSession) { 132 txId = ((TxSession) session).getTxId(); 133 } else { 134 txId = ""; 135 } 136 137 if (txId.isEmpty()) { 138 LOGGER.debug("cannot finalize an empty tx id {} at path {}", 139 txId, path); 140 return status(BAD_REQUEST).build(); 141 } 142 143 if (commit) { 144 LOGGER.debug("commiting transaction {} at path {}", txId, path); 145 txService.commit(txId); 146 147 } else { 148 LOGGER.debug("rolling back transaction {} at path {}", txId, 149 path); 150 txService.rollback(txId); 151 } 152 return noContent().build(); 153 } 154}