001/*
002 * #%L
003 * Netarchivesuite - harvester
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University 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.harvester.datamodel.extendedfield;
025
026import java.text.DecimalFormat;
027import java.text.ParseException;
028import java.text.SimpleDateFormat;
029import java.util.TimeZone;
030
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034import dk.netarkivet.common.exceptions.ArgumentNotValid;
035
036/**
037 * Class for constructing, validating, and keeping the default value for a single ExtendedField.
038 */
039public class ExtendedFieldDefaultValue {
040
041    /** The logger. */
042    private static final Logger log = LoggerFactory.getLogger(ExtendedFieldDefaultValue.class);
043
044    /** Array of strings considered to be "true" values. */
045    protected static final String[] possibleTrueValues = {"true", "t", "1"};
046    /** Array of strings considered to be "false" values. */
047    protected static final String[] possibleFalseValues = {"false", "f", "0"};
048    /** The valid state of this ExtendedFieldDefaultValue. */
049    protected final boolean valid;
050
051    /** The value of this ExtendedFieldDefaultValue. */
052    protected String value;
053    /** The formatting pattern of this ExtendedFieldDefaultValue. */
054    protected String format;
055    /** The datatype of this ExtendedFieldDefaultValue. */
056    protected int datatype;
057
058    /**
059     * Constructor for the ExtendedFieldDefaultValues class.
060     *
061     * @param aValue The given default value
062     * @param aFormat the given formatting pattern
063     * @param aDatatype the given datatype
064     */
065    public ExtendedFieldDefaultValue(String aValue, String aFormat, int aDatatype) {
066        value = aValue;
067        format = aFormat;
068        datatype = aDatatype;
069        valid = validate();
070    }
071
072    /**
073     * Validate the arguments to the constructor.
074     *
075     * @return true, if arguments are valid; false otherwise.
076     */
077    private boolean validate() {
078        boolean isValid = false;
079        switch (datatype) {
080        case ExtendedFieldDataTypes.STRING:
081            isValid = true; // Any kind of string currently accepted.
082            break;
083        case ExtendedFieldDataTypes.BOOLEAN:
084            if (value != null) { // null is never a valid boolean!
085                isValid = checkBoolean(value);
086            }
087            break;
088        case ExtendedFieldDataTypes.NUMBER:
089            if (value == null || value.length() == 0) { // no value no format check
090                isValid = true;
091                break;
092            }
093
094            if (format != null) {
095                if (format.length() == 0) {
096                    isValid = true;
097                    break;
098                }
099
100                DecimalFormat decimalFormat = new DecimalFormat(format);
101                try {
102                    decimalFormat.parse(value);
103                    isValid = true;
104                } catch (ParseException e) {
105                    log.debug("Invalid NUMBER: {}", value);
106                }
107            } else {
108                isValid = true;
109            }
110            break;
111        case ExtendedFieldDataTypes.TIMESTAMP:
112        case ExtendedFieldDataTypes.JSCALENDAR:
113            if (value == null || value.length() == 0) { // no value no format check
114                isValid = true;
115                break;
116            }
117
118            if (format != null) {
119                if (format.length() == 0) {
120                    isValid = true;
121                    break;
122                }
123
124                SimpleDateFormat dateFormat = new SimpleDateFormat(format);
125                try {
126                    dateFormat.parse(value);
127                    isValid = true;
128                } catch (ParseException e) {
129                    log.debug("Invalid TIMESTAMP: {}", value);
130                }
131            } else {
132                isValid = true;
133            }
134            break;
135        case ExtendedFieldDataTypes.NOTE:
136            isValid = true; // Any kind of NOTE value currently accepted.
137            break;
138        case ExtendedFieldDataTypes.SELECT:
139            isValid = true; // Any kind of SELECT value currently accepted.
140            break;
141        default:
142            throw new ArgumentNotValid("Unable to validate unknown datatype: " + datatype);
143        }
144
145        return isValid;
146    }
147
148    /**
149     * Check the given string if it can be parsed as a Boolean.
150     *
151     * @param aBooleanValue A given boolean
152     * @return true, if the given string if it can be parsed as a Boolean.
153     */
154    private static boolean checkBoolean(final String aBooleanValue) {
155        String aBooleanValueTrimmed = aBooleanValue.toLowerCase().trim();
156
157        for (String val : possibleTrueValues) {
158            if (aBooleanValueTrimmed.equals(val)) {
159                return true;
160            }
161        }
162
163        for (String val : possibleFalseValues) {
164            if (aBooleanValueTrimmed.equals(val)) {
165                return true;
166            }
167        }
168        log.debug("The string '{}' is not a valid Boolean value", aBooleanValue);
169        return false;
170    }
171
172    /**
173     * @return true, if ExtendedFieldDefaultValue is valid, false otherwise.
174     */
175    public boolean isValid() {
176        return valid;
177    }
178
179    /**
180     * @return String, the DB-Value of the a Value
181     */
182    public String getDBValue() {
183        // prevent that any null value fills content column of extendedFieldValue
184        if (value == null) {
185            value = "";
186        }
187
188        // only if datatype is Timestamp, JSCalendar or Number. Otherwise DB-Value = Value
189        if (value != null && value.length() > 0) {
190            if (ExtendedFieldDataTypes.TIMESTAMP == datatype || ExtendedFieldDataTypes.JSCALENDAR == datatype) {
191                try {
192                    // the Milliseconds from 1.1.1970 will be stored as String
193                    SimpleDateFormat sdf = new SimpleDateFormat(format);
194                    sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
195                    return String.valueOf(sdf.parse(value).getTime());
196                } catch (ParseException e) {
197                    log.debug("Invalid TIMESTAMP: {}", value);
198                }
199            } else if (ExtendedFieldDataTypes.NUMBER == datatype) {
200                try {
201                    // a Double Value will be stored String
202                    return String.valueOf(new DecimalFormat(format).parse(value).doubleValue());
203                } catch (ParseException e) {
204                    log.debug("Invalid NUMBER: {}", value);
205                }
206            }
207        }
208
209        return value;
210    }
211
212}