001/*
002 * #%L
003 * Netarchivesuite - common
004 * %%
005 * Copyright (C) 2005 - 2018 The Royal Danish Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.common.utils;
025
026import java.io.BufferedReader;
027import java.io.File;
028import java.io.FileReader;
029import java.io.IOException;
030
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034import dk.netarkivet.common.exceptions.ArgumentNotValid;
035
036/**
037 * Onb Free Space Provider returns the number of bytes free
038 * Returning 0 if a given path is not writable or if free space is lower than a given minimum free space percentage
039 */
040
041public class OnbFreeSpaceProvider implements FreeSpaceProvider {
042
043    /** The error logger we notify about error messages on. */
044    private static final Logger log = LoggerFactory.getLogger(OnbFreeSpaceProvider.class);
045
046    /** The default place in classpath where the settings file can be found. */
047    private static String DEFAULT_SETTINGS_CLASSPATH = "dk/netarkivet/common/utils/OnbFreeSpaceProviderSettings.xml";
048
049    /*
050     * The static initialiser is called when the class is loaded. It will add default values for all settings defined in
051     * this class, by loading them from a settings.xml file in classpath.
052     */
053    static {
054        Settings.addDefaultClasspathSettings(DEFAULT_SETTINGS_CLASSPATH);
055    }
056
057    /**
058     * <b>settings.common.freespaceprovider.minfreespacemode</b>: <br>
059     * The setting the mode for Provider
060     */
061    public static final String FREESPACEPROVIDER_FREESPACEMODE_SETTING = "settings.common.freespaceprovider.freespacemode";
062    /**
063     * <b>settings.common.freespaceprovider.minfreespacepercentage</b>: <br>
064     * The setting for minimum free space percentage
065     */
066    public static final String FREESPACEPROVIDER_MINFREESPACEPERCENTAGE_SETTING = "settings.common.freespaceprovider.minfreespacepercentage";
067    /**
068     * <b>settings.common.freespaceprovider.minfreespace</b>: <br>
069     * The setting for minimum free space in Bytes
070     */
071    public static final String FREESPACEPROVIDER_MINFREESPACE_SETTING = "settings.common.freespaceprovider.minfreespace";
072
073    /**
074     * The setting the mode for Provider (percent = percentage check, byte = byte check)
075     **/
076    private static final String FREESPACEPROVIDER_FREESPACEMODE = Settings.get(FREESPACEPROVIDER_FREESPACEMODE_SETTING);
077    
078    private static final String FREESPACEPROVIDER_FREESPACEMODE_PERCENTAGE = "percent";
079    private static final String FREESPACEPROVIDER_FREESPACEMODE_BYTE = "byte";
080    /**
081     * The minimum free space percentage
082     * e.g. 5 or 5.55
083     **/
084    private static final Double FREESPACEPROVIDER_MINFREESPACEPERCENTAGE = Double.parseDouble(Settings.get(FREESPACEPROVIDER_MINFREESPACEPERCENTAGE_SETTING));
085    /**
086     * The minimum free space in bytes
087     * e.g. 1000000 
088     **/
089    private static final long FREESPACEPROVIDER_MINFREESPACE = Long.parseLong(Settings.get(FREESPACEPROVIDER_MINFREESPACE_SETTING));
090
091    
092    /**
093     * Returns the number of bytes free on the file system that the given file resides on. Will return 0 on non-existing
094     * files, on read only files and if free space is lower than given freespacepercentage (in freespacemode percent) or 
095     * freespace (in freespacemode byte) in settings.
096     *
097     * @param f a given file
098     * @return the number of bytes free.
099     */
100    public long getBytesFree(File f) {
101        ArgumentNotValid.checkNotNull(f, "File f");
102        if (!f.exists()) {
103            log.warn("The file '{}' does not exist. The value 0 returned.", f.getAbsolutePath());
104            return 0;
105        }
106
107        if (!f.canWrite()) {
108            log.warn("The file '{}' is not writeable. The value 0 returned.", f.getAbsolutePath());
109            return 0;
110        }
111
112        log.debug("FreeSpaceMode is '{}'", FREESPACEPROVIDER_FREESPACEMODE);
113        
114        if (FREESPACEPROVIDER_FREESPACEMODE_PERCENTAGE.equals(FREESPACEPROVIDER_FREESPACEMODE)) {
115            long totalspace;
116            long usable;
117
118            totalspace = f.getTotalSpace();
119            usable = f.getUsableSpace();
120
121            double freeSpaceInPercent =  100.0 / totalspace * usable;
122            log.debug("minfreespacepercentage is '{}'", FREESPACEPROVIDER_MINFREESPACEPERCENTAGE);
123            log.debug("Free space in percent is '{}'", freeSpaceInPercent);
124                
125            if (freeSpaceInPercent <= FREESPACEPROVIDER_MINFREESPACEPERCENTAGE) {
126                log.warn("Free space on '{}' is lower than '{}' percent. The value 0 returned.", f.getAbsolutePath(), FREESPACEPROVIDER_MINFREESPACEPERCENTAGE);
127                return 0;
128            }
129            else {
130                return usable;
131            }
132        }
133
134        if (FREESPACEPROVIDER_FREESPACEMODE_BYTE.equals(FREESPACEPROVIDER_FREESPACEMODE)) {
135            log.debug("minfreespace is '{}'", FREESPACEPROVIDER_MINFREESPACE);           
136            log.debug("Free space in byte is '{}'", f.getUsableSpace());
137            
138            if (f.getUsableSpace() < FREESPACEPROVIDER_MINFREESPACE) {
139                log.warn("Free space on '{}' is lower than '{}' bytes. The value 0 returned.", f.getAbsolutePath(), FREESPACEPROVIDER_MINFREESPACE);
140                return 0;
141            }
142                else {
143                        return f.getUsableSpace(); 
144                }
145        }
146        
147        log.warn("Mode '{}' not valid. The value 0 returned.", FREESPACEPROVIDER_FREESPACEMODE_BYTE);
148        return 0;
149    }
150}