org.codice.ddf.catalog.content.monitor.DavEntry.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.catalog.content.monitor.DavEntry.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.ddf.catalog.content.monitor;

import com.github.sardine.DavResource;
import com.github.sardine.Sardine;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;

/**
 * A webdav implementation of the {@link org.apache.commons.io.monitor.FileEntry} Uses
 * https://github.com/lookfirst/sardine
 */
public class DavEntry implements Serializable {

    private static final long serialVersionUID = -2505664948818681153L;

    private static final DavEntry[] EMPTY_ENTRIES = new DavEntry[0];

    private static final String HTTP = "http";

    private static final String FORSLASH = "/";

    private final DavEntry parent;

    private DavEntry[] children;

    private File file;

    private String location;

    private boolean exists;

    private boolean directory;

    private long lastModified;

    private long length;

    private String eTag;

    /** @param location must be fully qualified */
    DavEntry(final String location) {
        this(null, location);
    }

    private DavEntry(final DavEntry parent, final String location) {
        if (location == null) {
            throw new IllegalArgumentException("File is missing");
        }
        this.parent = parent;
        this.setLocation(getLocation(location, parent));
    }

    static DavEntry[] getEmptyEntries() {
        return EMPTY_ENTRIES;
    }

    boolean refresh(DavResource davResource) {

        // cache original values
        final boolean origExists = isExists();
        final long origLastModified = getLastModified();
        final boolean origDirectory = isDirectory();
        final long origLength = getLength();
        final String origEtag = getETag();

        // refresh the values
        setExists(davResource != null);
        setDirectory(isExists() && davResource.isDirectory());
        setLastModified(isExists() && davResource.getModified() != null ? davResource.getModified().getTime() : 0);
        setLength(isExists() && !isDirectory() ? davResource.getContentLength() : 0);
        setETag(isExists() ? davResource.getEtag() : "0");

        if (file != null && !isDirectory() && origLastModified != getLastModified()) {
            deleteCacheIfExists();
        }

        // Return if there are changes
        return isExists() != origExists //
                || getLastModified() != origLastModified //
                || isDirectory() != origDirectory //
                || getLength() != origLength //
                || !Objects.equals(getETag(), origEtag);
    }

    DavEntry newChildInstance(String location) {
        return new DavEntry(this, location);
    }

    // construct the fully qualified location from a fully qualified parent and
    // a child relative to the parent
    static String getLocation(String initialLocation, DavEntry parent) {
        String location = initialLocation;
        if (parent != null && !location.startsWith(HTTP)) {
            String parentLocation = parent.getLocation();
            if (parentLocation.endsWith(FORSLASH) && location.startsWith(FORSLASH)) {
                location = location.replaceFirst(FORSLASH, "");
            }
            if (!parentLocation.endsWith(FORSLASH) && !location.startsWith(FORSLASH)) {
                location = FORSLASH + location;
            }
            location = parentLocation + location;
        }
        try {
            // URL class performs structural decomposition of location for us
            // URI class performs character encoding, but ONLY via multipart constructors
            // Finally, we have a fully qualified and escaped location for future manipulation
            URL url = new URL(location);
            URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(),
                    url.getQuery(), url.getRef());
            location = uri.toASCIIString();
        } catch (MalformedURLException | URISyntaxException e) {
            throw new RuntimeException(e);
        }
        return location;
    }

    /**
     * Return the parent entry.
     *
     * @return the parent entry
     */
    public DavEntry getParent() {
        return parent;
    }

    /**
     * Return the level
     *
     * @return the level
     */
    int getLevel() {
        return getParent() == null ? 0 : getParent().getLevel() + 1;
    }

    /**
     * Return the directory's files.
     *
     * @return This directory's files or an empty array if the file is not a directory or the
     *     directory is empty
     */
    DavEntry[] getChildren() {
        return children != null ? children : getEmptyEntries();
    }

    /**
     * Set the directory's files.
     *
     * @param children This directory's files, may be null
     */
    void setChildren(final DavEntry... children) {
        this.children = children;
    }

    /**
     * Return a local cache of the file being monitored. This file is invalidated if necessary when
     * refresh() is called.
     *
     * @param sardine
     * @return the file being monitored
     */
    public File getFile(Sardine sardine) throws IOException {
        if (file == null || !file.exists()) {
            Path dav = Files.createTempDirectory("dav");
            File dest = new File(dav.toFile(), URLDecoder.decode(FilenameUtils.getName(getLocation()), "UTF-8"));
            try (OutputStream os = new FileOutputStream(dest)) {
                IOUtils.copy(sardine.get(getLocation()), os);
                setFile(dest);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
        return file;
    }

    /**
     * Return the file location.
     *
     * @return the file location
     */
    public String getLocation() {
        return location;
    }

    /**
     * Set the file location.
     *
     * @param location the file location
     */
    public void setLocation(final String location) {
        this.location = location;
    }

    /**
     * Return the last modified time from the last time it was checked.
     *
     * @return the last modified time
     */
    public long getLastModified() {
        return lastModified;
    }

    /**
     * Return the last modified time from the last time it was checked.
     *
     * @param lastModified The last modified time
     */
    public void setLastModified(final long lastModified) {
        this.lastModified = lastModified;
    }

    /**
     * Return the length.
     *
     * @return the length
     */
    public long getLength() {
        return length;
    }

    /**
     * Set the length.
     *
     * @param length the length
     */
    public void setLength(final long length) {
        this.length = length;
    }

    /**
     * Indicate whether the file existed the last time it was checked.
     *
     * @return whether the file existed
     */
    public boolean isExists() {
        return exists;
    }

    /**
     * Set whether the file existed the last time it was checked.
     *
     * @param exists whether the file exists or not
     */
    public void setExists(final boolean exists) {
        this.exists = exists;
    }

    /**
     * Indicate whether the file is a directory or not.
     *
     * @return whether the file is a directory or not
     */
    public boolean isDirectory() {
        return directory;
    }

    /**
     * Set whether the file is a directory or not.
     *
     * @param directory whether the file is a directory or not
     */
    public void setDirectory(final boolean directory) {
        this.directory = directory;
    }

    /**
     * If this {@code DavEntry}'s file is cached, delete it. A {@code DavEntry}'s file is cached on
     * the first call to {@link #getFile(Sardine) DavEntry.getFile(Sardine)}.
     */
    public void deleteCacheIfExists() {
        if (file != null) {
            FileUtils.deleteQuietly(file.getParentFile());
        }
    }

    boolean remoteExists(Sardine sardine) {
        try {
            sardine.list(getLocation());
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    public String getETag() {
        return eTag;
    }

    void setFile(File file) {
        this.file = file;
    }

    void setETag(String eTag) {
        this.eTag = eTag;
    }
}