org.hsqldb.persist.HsqlProperties Maven / Gradle / Ivy
Show all versions of sqltool Show documentation
/* Copyright (c) 2001-2021, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb.persist;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.FileAccess;
import org.hsqldb.lib.FileUtil;
import org.hsqldb.lib.HashMap;
import org.hsqldb.map.ValuePool;
/**
* Wrapper for java.util.Properties to limit values to Specific types and
* allow saving and loading.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.5.1
* @since 1.7.0
*/
public class HsqlProperties {
//
public static final int ANY_ERROR = 0;
public static final int NO_VALUE_FOR_KEY = 1;
protected String fileName;
protected String fileExtension = "";
protected Properties stringProps;
protected int[] errorCodes = ValuePool.emptyIntArray;
protected String[] errorKeys = ValuePool.emptyStringArray;
protected FileAccess fa;
protected HashMap metaData;
public HsqlProperties() {
stringProps = new Properties();
fileName = null;
}
public HsqlProperties(String fileName) {
this(fileName, ".properties");
}
public HsqlProperties(String fileName, String fileExtension) {
stringProps = new Properties();
this.fileName = fileName;
this.fileExtension = fileExtension;
fa = FileUtil.getFileUtil();
}
public HsqlProperties(HashMap meta, String fileName, FileAccess accessor,
boolean b) {
stringProps = new Properties();
this.fileName = fileName;
this.fileExtension = ".properties";
fa = accessor;
metaData = meta;
}
public HsqlProperties(Properties props) {
stringProps = props;
}
public void setFileName(String name) {
fileName = name;
}
public String setProperty(String key, int value) {
return setProperty(key, Integer.toString(value));
}
public String setProperty(String key, boolean value) {
return setProperty(key, String.valueOf(value));
}
public String setProperty(String key, String value) {
return (String) stringProps.put(key, value);
}
public String setPropertyIfNotExists(String key, String value) {
value = getProperty(key, value);
return setProperty(key, value);
}
public Properties getProperties() {
return stringProps;
}
public String getProperty(String key) {
return stringProps.getProperty(key);
}
public String getProperty(String key, String defaultValue) {
return stringProps.getProperty(key, defaultValue);
}
public int getIntegerProperty(String key, int defaultValue) {
return getIntegerProperty(stringProps, key, defaultValue);
}
public static int getIntegerProperty(Properties props, String key,
int defaultValue) {
String prop = props.getProperty(key);
try {
if (prop != null) {
prop = prop.trim();
defaultValue = Integer.parseInt(prop);
}
} catch (NumberFormatException e) {}
return defaultValue;
}
public boolean isPropertyTrue(String key) {
return isPropertyTrue(key, false);
}
public boolean isPropertyTrue(String key, boolean defaultValue) {
String value = stringProps.getProperty(key);
if (value == null) {
return defaultValue;
}
value = value.trim();
return value.toLowerCase().equals("true");
}
public void removeProperty(String key) {
stringProps.remove(key);
}
public void addProperties(Properties props) {
if (props == null) {
return;
}
Enumeration keys = props.propertyNames();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
String value = props.getProperty(key);
this.stringProps.put(key, value);
}
}
public void addProperties(HsqlProperties props) {
if (props == null) {
return;
}
addProperties(props.stringProps);
}
// [email protected]
public boolean propertiesFileExists() {
if (fileName == null) {
return false;
}
String propFilename = fileName + fileExtension;
return fa.isStreamElement(propFilename);
}
public boolean load() throws Exception {
if (fileName == null || fileName.isEmpty()) {
throw new FileNotFoundException(
Error.getMessage(ErrorCode.M_HsqlProperties_load));
}
if (!propertiesFileExists()) {
return false;
}
InputStream fis = null;
String propsFilename = fileName + fileExtension;
// [email protected]
try {
fis = fa.openInputStreamElement(propsFilename);
stringProps.load(fis);
} finally {
if (fis != null) {
fis.close();
}
}
return true;
}
/**
* Saves the properties.
*/
public void save() throws Exception {
if (fileName == null || fileName.isEmpty()) {
throw new java.io.FileNotFoundException(
Error.getMessage(ErrorCode.M_HsqlProperties_load));
}
String filestring = fileName + fileExtension;
save(filestring);
}
/**
* Saves the properties
*/
public void save(String fileString) throws Exception {
// [email protected]
fa.createParentDirs(fileString);
fa.removeElement(fileString);
OutputStream fos = fa.openOutputStreamElement(fileString);
FileAccess.FileSync outDescriptor = fa.getFileSync(fos);
String name = HsqlDatabaseProperties.PRODUCT_NAME + " "
+ HsqlDatabaseProperties.THIS_FULL_VERSION;
stringProps.store(fos, name);
fos.flush();
outDescriptor.sync();
fos.close();
outDescriptor = null;
fos = null;
}
/**
* Adds the error code and the key to the list of errors. This list
* is populated during construction or addition of elements and is used
* outside this class to act upon the errors.
*/
protected void addError(int code, String key) {
errorCodes = (int[]) ArrayUtil.resizeArray(errorCodes,
errorCodes.length + 1);
errorKeys = (String[]) ArrayUtil.resizeArray(errorKeys,
errorKeys.length + 1);
errorCodes[errorCodes.length - 1] = code;
errorKeys[errorKeys.length - 1] = key;
}
/**
* Creates and populates an HsqlProperties Object from the arguments
* array of a Main method. Properties are in the form of "-key value"
* pairs. Each key is prefixed with the type argument and a dot before
* being inserted into the properties Object.
*
* "--help" is treated as a key with no value and not inserted.
*/
public static HsqlProperties argArrayToProps(String[] arg, String type) {
HsqlProperties props = new HsqlProperties();
for (int i = 0; i < arg.length; i++) {
String p = arg[i];
if (p.equals("--help") || p.equals("-help")) {
props.addError(NO_VALUE_FOR_KEY, p.substring(1));
} else if (p.startsWith("--")) {
String value = i + 1 < arg.length ? arg[i + 1]
: "";
props.setProperty(type + "." + p.substring(2), value);
i++;
} else if (p.charAt(0) == '-') {
String value = i + 1 < arg.length ? arg[i + 1]
: "";
props.setProperty(type + "." + p.substring(1), value);
i++;
}
}
return props;
}
/**
* Creates and populates a new HsqlProperties Object using a string
* such as "key1=value1;key2=value2".
*
* The string that represents the = sign above is specified as pairsep
* and the one that represents the semicolon is specified as delimiter,
* allowing any string to be used for either.
*
* Leading / trailing spaces around the keys and values are discarded.
*
* The string is parsed by (1) subdividing into segments by delimiter
* (2) subdividing each segment in two by finding the first instance of
* the pairsep (3) trimming each pair of segments from step 2 and
* inserting into the properties object.
*
* Each key is prefixed with the type argument and a dot before being
* inserted.
*
* Any key without a value is added to the list of errors.
*/
public static HsqlProperties delimitedArgPairsToProps(String s,
String pairsep, String dlimiter, String type) {
HsqlProperties props = new HsqlProperties();
int currentpair = 0;
while (true) {
int nextpair = s.indexOf(dlimiter, currentpair);
if (nextpair == -1) {
nextpair = s.length();
}
// find value within the segment
int valindex = s.substring(0, nextpair).indexOf(pairsep,
currentpair);
if (valindex == -1) {
props.addError(NO_VALUE_FOR_KEY,
s.substring(currentpair, nextpair).trim());
} else {
String key = s.substring(currentpair, valindex).trim();
String value = s.substring(valindex + pairsep.length(),
nextpair).trim();
if (type != null) {
key = type + "." + key;
}
props.setProperty(key, value);
}
if (nextpair == s.length()) {
break;
}
currentpair = nextpair + dlimiter.length();
}
return props;
}
public Enumeration propertyNames() {
return stringProps.propertyNames();
}
public boolean isEmpty() {
return stringProps.isEmpty();
}
public String[] getErrorKeys() {
return errorKeys;
}
public void validate() {}
// column number mappings
public static final int indexName = 0;
public static final int indexType = 1;
public static final int indexClass = 2;
public static final int indexIsRange = 3;
public static final int indexDefaultValue = 4;
public static final int indexRangeLow = 5;
public static final int indexRangeHigh = 6;
public static final int indexValues = 7;
public static final int indexLimit = 9;
public static Object[] getMeta(String name, int type) {
Object[] row = new Object[indexLimit];
row[indexName] = name;
row[indexType] = ValuePool.getInt(type);
row[indexClass] = "Long";
row[indexDefaultValue] = Long.valueOf(0);
return row;
}
public static Object[] getMeta(String name, int type,
String defaultValue) {
Object[] row = new Object[indexLimit];
row[indexName] = name;
row[indexType] = ValuePool.getInt(type);
row[indexClass] = "String";
row[indexDefaultValue] = defaultValue;
return row;
}
public static Object[] getMeta(String name, int type,
boolean defaultValue) {
Object[] row = new Object[indexLimit];
row[indexName] = name;
row[indexType] = ValuePool.getInt(type);
row[indexClass] = "Boolean";
row[indexDefaultValue] = defaultValue ? Boolean.TRUE
: Boolean.FALSE;
return row;
}
public static Object[] getMeta(String name, int type, int defaultValue,
int[] values) {
Object[] row = new Object[indexLimit];
row[indexName] = name;
row[indexType] = ValuePool.getInt(type);
row[indexClass] = "Integer";
row[indexDefaultValue] = ValuePool.getInt(defaultValue);
row[indexValues] = values;
return row;
}
public static Object[] getMeta(String name, int type, int defaultValue,
int rangeLow, int rangeHigh) {
Object[] row = new Object[indexLimit];
row[indexName] = name;
row[indexType] = ValuePool.getInt(type);
row[indexClass] = "Integer";
row[indexDefaultValue] = ValuePool.getInt(defaultValue);
row[indexIsRange] = Boolean.TRUE;
row[indexRangeLow] = ValuePool.getInt(rangeLow);
row[indexRangeHigh] = ValuePool.getInt(rangeHigh);
return row;
}
/**
* Performs any range checking for property and return an error message
*/
public static String validateProperty(String key, String value,
Object[] meta) {
if (meta[indexClass].equals("Boolean")) {
value = value.toLowerCase();
if (value.equals("true") || value.equals("false")) {
return null;
}
return "invalid boolean value for property: " + key;
}
if (meta[indexClass].equals("String")) {
return null;
}
if (meta[indexClass].equals("Long")) {
return null;
}
if (meta[indexClass].equals("Integer")) {
try {
int number = Integer.parseInt(value);
if (Boolean.TRUE.equals(meta[indexIsRange])) {
int low = ((Integer) meta[indexRangeLow]).intValue();
int high = ((Integer) meta[indexRangeHigh]).intValue();
if (number < low || high < number) {
return "value outside range for property: " + key;
}
}
if (meta[indexValues] != null) {
int[] values = (int[]) meta[indexValues];
if (ArrayUtil.find(values, number) == -1) {
return "value not supported for property: " + key;
}
}
} catch (NumberFormatException e) {
return "invalid integer value for property: " + key;
}
return null;
}
return null;
}
public int getPropertyWithinRange(String name, int number) {
Object[] meta = (Object[]) metaData.get(name);
if (meta == null) {
return number;
}
if (meta[indexClass].equals("Integer")) {
if (Boolean.TRUE.equals(meta[indexIsRange])) {
int low = ((Integer) meta[indexRangeLow]).intValue();
int high = ((Integer) meta[indexRangeHigh]).intValue();
if (number < low) {
return low;
} else if (high < number) {
return high;
}
}
if (meta[indexValues] != null) {
int[] values = (int[]) meta[indexValues];
if (ArrayUtil.find(values, number) == -1) {
return values[0];
}
}
}
return number;
}
public boolean validateProperty(String name, int number) {
Object[] meta = (Object[]) metaData.get(name);
if (meta == null) {
return false;
}
if (meta[indexClass].equals("Integer")) {
if (Boolean.TRUE.equals(meta[indexIsRange])) {
int low = ((Integer) meta[indexRangeLow]).intValue();
int high = ((Integer) meta[indexRangeHigh]).intValue();
if (number < low || high < number) {
return false;
}
}
if (meta[indexValues] != null) {
int[] values = (int[]) meta[indexValues];
if (ArrayUtil.find(values, number) == -1) {
return false;
}
}
return true;
}
return false;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('{');
int len = stringProps.size();
Enumeration en = stringProps.propertyNames();
List list = Collections.list(en);
Collections.sort(list);
for (int i = 0; i < len; i++) {
String key = (String) list.get(i);
sb.append(key);
sb.append('=');
sb.append('"');
sb.append(stringProps.get(key));
sb.append('"');
if (i + 1 < len) {
sb.append(',');
sb.append(' ');
}
}
sb.append('}');
return sb.toString();
}
}