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 java.lang.String.format;
021import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
022import static javax.ws.rs.core.Response.status;
023import static org.fcrepo.http.commons.domain.RDFMediaType.TEXT_PLAIN_WITH_CHARSET;
024import static org.slf4j.LoggerFactory.getLogger;
025
026import javax.inject.Inject;
027import javax.ws.rs.BadRequestException;
028import javax.ws.rs.DELETE;
029import javax.ws.rs.GET;
030import javax.ws.rs.POST;
031import javax.ws.rs.PUT;
032import javax.ws.rs.Path;
033import javax.ws.rs.PathParam;
034import javax.ws.rs.Produces;
035import javax.ws.rs.core.Response;
036
037import org.fcrepo.kernel.api.identifiers.FedoraId;
038import org.fcrepo.kernel.api.services.ReindexService;
039
040import org.apache.http.HttpStatus;
041import org.slf4j.Logger;
042import org.springframework.context.annotation.Scope;
043
044import io.micrometer.core.annotation.Timed;
045
046/**
047 * @author dbernstein
048 * @since 12/01/20
049 */
050@Timed
051@Scope("request")
052@Path("/{path: (.+/)?}fcr:reindex")
053public class FedoraReindex extends FedoraBaseResource {
054
055    private static final Logger LOGGER = getLogger(FedoraReindex.class);
056
057    @Inject
058    private ReindexService reindexService;
059
060    @PathParam("path")
061    protected String externalPath;
062
063    /**
064     * Default JAX-RS entry point
065     */
066    public FedoraReindex() {
067        super();
068    }
069
070    /**
071     * Reindex a fedora resource.
072     *
073     * @return A response
074     */
075    @POST
076    @Produces({APPLICATION_JSON + ";qs=1.0",
077            TEXT_PLAIN_WITH_CHARSET})
078    public Response reindexObject() {
079        LOGGER.info("receiving reindex request for fedora_id = {}", externalPath);
080        try {
081            final var transaction = transaction();
082            final var id = FedoraId.create(externalPath);
083            if (doesResourceExist(transaction, id, true)) {
084                //TODO : remove this block once reindexing of existing resources is supported.
085                //       c.f.  https://jira.lyrasis.org/browse/FCREPO-3553
086                return status(HttpStatus.SC_CONFLICT, "Reindexing of existing resources is not currently supported. " +
087                        "Only resources that have not yet been indexed are allowed.").build();
088            } else {
089                try {
090                    final var baseId = id.asBaseId();
091
092                    doInDbTxWithRetry(() -> {
093                        this.reindexService.reindexByFedoraId(transaction(), getUserPrincipal(), baseId);
094                        transaction.commitIfShortLived();
095                    });
096
097                    final var message = format("successfully reindexed %s", id.getBaseId());
098                    LOGGER.info(message);
099                    return status(HttpStatus.SC_NO_CONTENT).entity(message).build();
100                } finally {
101                    transaction().releaseResourceLocksIfShortLived();
102                }
103            }
104
105        } catch (final Exception ex) {
106            throw new BadRequestException(ex.getMessage(), ex);
107        }
108    }
109
110    @DELETE
111    public Response delete() {
112        return methodNotAllowed();
113    }
114
115    @PUT
116    public Response put() {
117        return methodNotAllowed();
118    }
119
120    @GET
121    public Response get() {
122        return methodNotAllowed();
123    }
124
125    private Response methodNotAllowed() {
126        return status(HttpStatus.SC_METHOD_NOT_ALLOWED).build();
127    }
128
129
130}
131