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.repository;
019
020import static com.google.common.io.Files.createTempDir;
021import static java.util.stream.Collectors.joining;
022import static javax.ws.rs.core.Response.serverError;
023import static org.slf4j.LoggerFactory.getLogger;
024
025import java.io.File;
026import java.io.IOException;
027import java.io.InputStream;
028import java.util.Collection;
029
030import javax.inject.Inject;
031import javax.jcr.Session;
032import javax.ws.rs.POST;
033import javax.ws.rs.Path;
034import javax.ws.rs.WebApplicationException;
035
036import org.apache.commons.io.IOUtils;
037import org.fcrepo.http.commons.AbstractResource;
038import org.fcrepo.kernel.api.services.RepositoryService;
039import org.slf4j.Logger;
040import org.springframework.context.annotation.Scope;
041
042/**
043 * Repository-wide backup endpoint
044 *
045 * @author cbeer
046 */
047@Scope("prototype")
048@Path("/fcr:backup")
049public class FedoraRepositoryBackup extends AbstractResource {
050
051    private static final Logger LOGGER = getLogger(FedoraRepositoryBackup.class);
052
053    @Inject
054    protected Session session;
055
056    /**
057     * The fcrepo repository service
058     */
059    @Inject
060    protected RepositoryService repositoryService;
061
062    /**
063     * This method runs a repository backup.
064     *
065     * @param bodyStream the input body stream
066     * @return path to the backup
067     * @throws IOException if IO exception occurred
068     */
069    @POST
070    public String runBackup(final InputStream bodyStream) throws IOException {
071
072        File backupDirectory;
073        if (null != bodyStream) {
074            final String body = IOUtils.toString(bodyStream).trim();
075
076            backupDirectory = new File(body.trim());
077            if (body.isEmpty()) {
078                // Backup to a temp directory
079                backupDirectory = createTempDir();
080
081            } else if (!backupDirectory.exists() || !backupDirectory.canWrite()) {
082                throw new WebApplicationException(
083                        serverError().entity(
084                                "Backup directory does not exist or is not writable: " +
085                                        backupDirectory.getAbsolutePath())
086                                .build());
087            }
088
089        } else {
090            // Backup to a temp directory
091            backupDirectory = createTempDir();
092        }
093
094        LOGGER.debug("Backing up to: {}", backupDirectory.getAbsolutePath());
095        final Collection<Throwable> problems = repositoryService.backupRepository(session, backupDirectory);
096
097        if (!problems.isEmpty()) {
098            LOGGER.error("Problems backing up the repository:");
099
100            // Report the problems (we'll just print them out) ...
101            final String output = problems.stream().map(Throwable::getMessage).peek(LOGGER::error)
102                    .collect(joining("\n"));
103
104            throw new WebApplicationException(serverError().entity(output).build());
105
106        }
107        return backupDirectory.getCanonicalPath();
108    }
109}