From: gotty Date: Thu, 16 May 2019 11:11:30 +0000 (+0000) Subject: [LIB-4] Transition to typed properties X-Git-Url: https://git.hedgecode.org/?p=hespiff.git;a=commitdiff_plain;h=d50a7fa6952079a2685cf740cf221b69a4e5fafa;hp=ad6e6a2426c97aa14868d9bd2d279efc84c890d8 [LIB-4] Transition to typed properties git-svn-id: https://svn.hedgecode.org/xml/hespiff/trunk@169 fb0bcced-7025-49ed-a12f-f98bce993226 --- diff --git a/src/main/java/org/hedgecode/xml/xspf/Properties.java b/src/main/java/org/hedgecode/xml/xspf/Properties.java deleted file mode 100644 index edf2d6c..0000000 --- a/src/main/java/org/hedgecode/xml/xspf/Properties.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2015-2019. Developed by Hedgecode. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.hedgecode.xml.xspf; - -import java.util.HashMap; -import java.util.Map; - -/** - * - * - * @author Dmitry Samoshin aka gotty - */ -public final class Properties { - - public static final String CHARSET = "xspf.charset"; - public static final String FORMATTED = "xspf.formatted"; - public static final String STANDALONE = "xspf.standalone"; - - private static final Map props = new HashMap() { - { - put(CHARSET, XSPFConstants.DEF_CHARSET); - put(FORMATTED, Boolean.TRUE); - put(STANDALONE, Boolean.FALSE); - } - }; - - public static void setProperty(String name, Object value) { - if (props.containsKey(name)) { - if (props.get(name).getClass().equals(value.getClass())) - props.put(name, value); - } - } - - public static Object getProperty(String name, Class clazz) { - if (clazz != null && props.containsKey(name)) { - Object property = props.get(name); - if (clazz.isAssignableFrom(property.getClass())) - return property; - } - return null; - } - - private Properties() { - throw new AssertionError( - "I am so paranoid!" - ); - } - -} diff --git a/src/main/java/org/hedgecode/xml/xspf/TypedProperties.java b/src/main/java/org/hedgecode/xml/xspf/TypedProperties.java new file mode 100644 index 0000000..7e73b91 --- /dev/null +++ b/src/main/java/org/hedgecode/xml/xspf/TypedProperties.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2015-2019. Developed by Hedgecode. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hedgecode.xml.xspf; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.Properties; + +/** + * Storage class represents a persistent set of typed properties. + * + * @author Dmitry Samoshin aka gotty + */ +public class TypedProperties extends Properties { + + public TypedProperties() { + this(null); + } + + public TypedProperties(TypedProperties defaults) { + super(defaults); + } + + public T getProperty(String key, Class type) { + Object object = get(key); + T val = type.isInstance(object) ? type.cast(object) : null; + return val == null + ? getDefProperty(key, type) + : val; + } + + public T getProperty(String key, Class type, T defaultValue) { + T val = getProperty(key, type); + return val == null ? defaultValue : val; + } + + public synchronized Object setProperty(String key, Object value) { + return put(key, value); + } + + protected T getDefProperty(String key, Class type) { + if (defaults != null) { + Object object = defaults.get(key); + return type.isInstance(object) ? type.cast(object) : null; + } + return null; + } + + @Override + public synchronized void load(Reader reader) throws IOException { + super.load(reader); + TypeSupport.cast(this); + } + + @Override + public synchronized void load(InputStream inStream) throws IOException { + super.load(inStream); + TypeSupport.cast(this); + } + + public String getString(String key) { + return getProperty(key, String.class); + } + + public Byte getByte(String key) { + return getProperty(key, Byte.class); + } + + public Short getShort(String key) { + return getProperty(key, Short.class); + } + + public Integer getInteger(String key) { + return getProperty(key, Integer.class); + } + + public Long getLong(String key) { + return getProperty(key, Long.class); + } + + public Float getFloat(String key) { + return getProperty(key, Float.class); + } + + public Double getDouble(String key) { + return getProperty(key, Double.class); + } + + public Character getCharacter(String key) { + return getProperty(key, Character.class); + } + + public Boolean getBoolean(String key) { + return getProperty(key, Boolean.class); + } + + private enum TypeSupport { + + INT ( "^-?\\d+$" ) { + + @Override + Object parse(String value) { + return Integer.parseInt(value); + } + + }, + + FLOAT ( "^-?[\\d.]+$" ) { + + @Override + Object parse(String value) { + return Float.parseFloat(value); + } + + }, + + BOOLEAN ( "^(TRUE|FALSE|[Tt]rue|[Ff]alse)$" ) { + + @Override + Object parse(String value) { + return Boolean.parseBoolean(value); + } + + }; + + private final String regex; + + TypeSupport(String regex) { + this.regex = regex; + } + + abstract Object parse(String value); + + static TypeSupport getType(String value) { + if (value != null) { + for (TypeSupport typeSupport : TypeSupport.values()) { + if (value.matches(typeSupport.regex)) { + return typeSupport; + } + } + } + return null; + } + + static void cast(Properties props) { + props.forEach((key, val) -> { + if (String.class.isInstance(val)) { + String value = (String) val; + TypeSupport typeSupport = getType(value); + if (typeSupport != null) { + props.replace(key, typeSupport.parse(value)); + } + } + }); + } + + } + +} \ No newline at end of file diff --git a/src/main/java/org/hedgecode/xml/xspf/XMLBindPlaylist.java b/src/main/java/org/hedgecode/xml/xspf/XMLBindPlaylist.java index 0ae5a5c..d554207 100644 --- a/src/main/java/org/hedgecode/xml/xspf/XMLBindPlaylist.java +++ b/src/main/java/org/hedgecode/xml/xspf/XMLBindPlaylist.java @@ -166,9 +166,7 @@ public class XMLBindPlaylist extends AbstractXMLBindElement implements Playlist public String getAsString() throws JAXBException, UnsupportedEncodingException { - Charset charset = (Charset) Properties.getProperty( - Properties.CHARSET, Charset.class - ); + Charset charset = XSPFProperties.getCharset(); ByteArrayOutputStream os = (ByteArrayOutputStream) getAsStream(); return os.toString( charset.name() @@ -178,17 +176,16 @@ public class XMLBindPlaylist extends AbstractXMLBindElement implements Playlist private Marshaller createMarshaller(Class xmlRootClass) throws JAXBException { JAXBContext jaxbContext = JAXBContext.newInstance(xmlRootClass); Marshaller marshaller = jaxbContext.createMarshaller(); - Charset charset = (Charset) Properties.getProperty(Properties.CHARSET, Charset.class); + Charset charset = XSPFProperties.getCharset(); marshaller.setProperty( Marshaller.JAXB_ENCODING, charset.name() ); marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, - Properties.getProperty(Properties.FORMATTED, Boolean.class) + XSPFProperties.getBoolean(XSPFProperties.FORMATTED) ); - Object standalone = Properties.getProperty(Properties.STANDALONE, Boolean.class); - if (Boolean.FALSE.equals(standalone)) { + if (Boolean.FALSE.equals(XSPFProperties.getBoolean(XSPFProperties.STANDALONE))) { marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); marshaller.setProperty( XSPFConstants.XML_HEADER_NAME, diff --git a/src/main/java/org/hedgecode/xml/xspf/XSPF.java b/src/main/java/org/hedgecode/xml/xspf/XSPF.java index 6da9754..4e39e8d 100644 --- a/src/main/java/org/hedgecode/xml/xspf/XSPF.java +++ b/src/main/java/org/hedgecode/xml/xspf/XSPF.java @@ -117,7 +117,7 @@ public final class XSPF { } public static void setProperty(String name, Object value) { - Properties.setProperty(name, value); + XSPFProperties.setProperty(name, value); } public static int validate(File inputFile) throws JAXBException { diff --git a/src/main/java/org/hedgecode/xml/xspf/XSPFProperties.java b/src/main/java/org/hedgecode/xml/xspf/XSPFProperties.java new file mode 100644 index 0000000..965cd81 --- /dev/null +++ b/src/main/java/org/hedgecode/xml/xspf/XSPFProperties.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015-2019. Developed by Hedgecode. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hedgecode.xml.xspf; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +/** + * XSPF API properties holder. + * + * @author Dmitry Samoshin aka gotty + */ +public final class XSPFProperties { + + /** Charset. */ + public static final String CHARSET = "xspf.charset"; + + /** Formatted output. */ + public static final String FORMATTED = "xspf.formatted.output"; + + /** Standalone. */ + public static final String STANDALONE = "xspf.standalone"; + + /** Version. */ + public static final String VERSION = "xspf.version"; + + /** Inception year. */ + public static final String INCEPTION_YEAR = "xspf.inception.year"; + + /** Properties file. */ + private static final String PROPERTIES_FILE = "xspf.properties"; + + /** Properties. */ + private static final TypedProperties PROPERTIES; + + /** + * Static properties initialization. + */ + static { + TypedProperties defaults = new TypedProperties() { + { + setProperty(CHARSET, XSPFConstants.DEF_CHARSET.name()); + setProperty(FORMATTED, Boolean.TRUE); + setProperty(STANDALONE, Boolean.FALSE); + } + }; + PROPERTIES = new TypedProperties(defaults); + readProperties(PROPERTIES_FILE, PROPERTIES, true); + } + + /** + * Read settings from properties file. + * + * @param propsFile properties file name. + * @param props properties. + * @param throwExc flag indicating whether to throw an exception or not. + */ + private static void readProperties(String propsFile, TypedProperties props, boolean throwExc) { + try (InputStream is = XSPFProperties.class.getClassLoader().getResourceAsStream(propsFile)) { + if (is == null) { + if (throwExc) + throw new RuntimeException("Failed to find properties file: " + propsFile); + else + return; + } + props.load(is); + } + catch (IOException e) { + throw new RuntimeException("Failed to read properties file: " + propsFile, e); + } + } + + /** + * Empty string for not found properties. + */ + private static final String EMPTY = ""; + + /** + * Get string property value. + * + * @param key property key. + * @return string value in the property list with the specified key value or empty string. + */ + public static String getString(String key) { + return PROPERTIES.getProperty(key, String.class, EMPTY); + } + + /** + * Get boolean property value or null if key not found. + * + * @param key property key. + * @return boolean value in the property list with the specified key value. + */ + public static Boolean getBoolean(String key) { + return PROPERTIES.getBoolean(key); + } + + /** + * Get boolean property value or default value if key not found. + * + * @param key property key. + * @param defaultValue default value if key not found. + * @return boolean value in the property list with the specified key value. + */ + public static Boolean getBoolean(String key, boolean defaultValue) { + return PROPERTIES.getProperty(key, Boolean.class, defaultValue); + } + + /** + * Get integer property value or null if key not found.. + * + * @param key property key. + * @return integer value in the property list with the specified key value. + */ + public static Integer getInteger(String key) { + return PROPERTIES.getInteger(key); + } + + /** + * Get integer property value or default value if key not found.. + * + * @param key property key. + * @param defaultValue default value if key not found. + * @return integer value in the property list with the specified key value. + */ + public static Integer getInteger(String key, int defaultValue) { + return PROPERTIES.getProperty(key, Integer.class, defaultValue); + } + + /** + * Get charset. + * + * @return charset value in the property list or default charset value. + */ + public static Charset getCharset() { + return Charset.forName( + PROPERTIES.getString(CHARSET) + ); + } + + /** + * Set property value. + * + * @param key key to be placed into this property list. + * @param value value corresponding to key. + */ + public static void setProperty(String key, Object value) { + if (PROPERTIES.containsKey(key)) { + if (PROPERTIES.get(key).getClass().isInstance(value)) { + PROPERTIES.replace(key, value); + } + } else { + PROPERTIES.setProperty(key, value); + } + } + + /** + * Private constructor. + */ + private XSPFProperties() { + } + +} diff --git a/src/main/resources/xspf.properties b/src/main/resources/xspf.properties new file mode 100644 index 0000000..e59c2b7 --- /dev/null +++ b/src/main/resources/xspf.properties @@ -0,0 +1,16 @@ +# Copyright (c) 2015-2019. Developed by Hedgecode. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +xspf.version=0.1-SNAPSHOT +xspf.inception.year=2015