/* * Licensed to DuraSpace under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * DuraSpace licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fcrepo.http.api; import static java.util.Date.from; import static javax.ws.rs.core.Response.created; import static javax.ws.rs.core.Response.noContent; import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static org.slf4j.LoggerFactory.getLogger; import java.net.URI; import java.net.URISyntaxException; import javax.inject.Inject; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; import org.fcrepo.kernel.api.services.BatchService; import org.slf4j.Logger; import org.springframework.context.annotation.Scope; /** * Transactions over REST * * @author awoods * @author gregjan */ @Scope("prototype") @Path("/{path: .*}/fcr:tx") public class FedoraTransactions extends FedoraBaseResource { private static final Logger LOGGER = getLogger(FedoraTransactions.class); @Inject protected BatchService batchService; /** * Create a new transaction resource and add it to the registry * * @param externalPath the external path * @return 201 with the transaction id and expiration date * @throws URISyntaxException if URI syntax exception occurred */ @POST public Response createTransaction(@PathParam("path") final String externalPath) throws URISyntaxException { if (batchService.exists(session.getId(), getUserPrincipal())) { LOGGER.debug("renewing transaction {}", session.getId()); batchService.refresh(session.getId(), getUserPrincipal()); final Response.ResponseBuilder res = noContent(); session.getFedoraSession().getExpires().ifPresent(expires -> { res.expires(from(expires)); }); return res.build(); } if (externalPath != null && !externalPath.isEmpty()) { return status(BAD_REQUEST).build(); } batchService.begin(session.getFedoraSession(), getUserPrincipal()); session.makeBatchSession(); LOGGER.info("Created transaction '{}'", session.getId()); final Response.ResponseBuilder res = created( new URI(translator().toDomain("/tx:" + session.getId()).toString())); session.getFedoraSession().getExpires().ifPresent(expires -> { res.expires(from(expires)); }); return res.build(); } /** * Commit a transaction resource * * @param externalPath the external path * @return 204 */ @POST @Path("fcr:commit") public Response commit(@PathParam("path") final String externalPath) { LOGGER.info("Commit transaction '{}'", externalPath); return finalizeTransaction(externalPath, getUserPrincipal(), true); } /** * Rollback a transaction * * @param externalPath the external path * @return 204 */ @POST @Path("fcr:rollback") public Response rollback(@PathParam("path") final String externalPath) { LOGGER.info("Rollback transaction '{}'", externalPath); return finalizeTransaction(externalPath, getUserPrincipal(), false); } private Response finalizeTransaction(@PathParam("path") final String externalPath, final String username, final boolean commit) { final String path = toPath(translator(), externalPath); if (!path.equals("/")) { return status(BAD_REQUEST).build(); } if (!session.isBatchSession()) { LOGGER.debug("cannot finalize an empty tx id {} at path {}", session.getId(), path); return status(BAD_REQUEST).build(); } if (commit) { LOGGER.debug("commiting transaction {} at path {}", session.getId(), path); batchService.commit(session.getId(), username); } else { LOGGER.debug("rolling back transaction {} at path {}", session.getId(), path); batchService.abort(session.getId(), username); } return noContent().build(); } }