[LIB-4] Transition to typed properties
[hespiff.git] / src / main / java / org / hedgecode / xml / xspf / TypedProperties.java
1 /*
2  * Copyright (c) 2015-2019. Developed by Hedgecode.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.hedgecode.xml.xspf;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.Reader;
22 import java.util.Properties;
23
24 /**
25  * Storage class represents a persistent set of typed properties.
26  *
27  * @author Dmitry Samoshin aka gotty
28  */
29 public class TypedProperties extends Properties {
30
31     public TypedProperties() {
32         this(null);
33     }
34
35     public TypedProperties(TypedProperties defaults) {
36         super(defaults);
37     }
38
39     public <T> T getProperty(String key, Class<T> type) {
40         Object object = get(key);
41         T val = type.isInstance(object) ? type.cast(object) : null;
42         return val == null
43                 ? getDefProperty(key, type)
44                 : val;
45     }
46
47     public <T> T getProperty(String key, Class<T> type, T defaultValue) {
48         T val = getProperty(key, type);
49         return val == null ? defaultValue : val;
50     }
51
52     public synchronized Object setProperty(String key, Object value) {
53         return put(key, value);
54     }
55
56     protected <T> T getDefProperty(String key, Class<T> type) {
57         if (defaults != null) {
58             Object object = defaults.get(key);
59             return type.isInstance(object) ? type.cast(object) : null;
60         }
61         return null;
62     }
63
64     @Override
65     public synchronized void load(Reader reader) throws IOException {
66         super.load(reader);
67         TypeSupport.cast(this);
68     }
69
70     @Override
71     public synchronized void load(InputStream inStream) throws IOException {
72         super.load(inStream);
73         TypeSupport.cast(this);
74     }
75
76     public String getString(String key) {
77         return getProperty(key, String.class);
78     }
79
80     public Byte getByte(String key) {
81         return getProperty(key, Byte.class);
82     }
83
84     public Short getShort(String key) {
85         return getProperty(key, Short.class);
86     }
87
88     public Integer getInteger(String key) {
89         return getProperty(key, Integer.class);
90     }
91
92     public Long getLong(String key) {
93         return getProperty(key, Long.class);
94     }
95
96     public Float getFloat(String key) {
97         return getProperty(key, Float.class);
98     }
99
100     public Double getDouble(String key) {
101         return getProperty(key, Double.class);
102     }
103
104     public Character getCharacter(String key) {
105         return getProperty(key, Character.class);
106     }
107
108     public Boolean getBoolean(String key) {
109         return getProperty(key, Boolean.class);
110     }
111
112     private enum TypeSupport {
113
114         INT ( "^-?\\d+$" ) {
115
116             @Override
117             Object parse(String value) {
118                 return Integer.parseInt(value);
119             }
120
121         },
122
123         FLOAT ( "^-?[\\d.]+$" ) {
124
125             @Override
126             Object parse(String value) {
127                 return Float.parseFloat(value);
128             }
129
130         },
131
132         BOOLEAN ( "^(TRUE|FALSE|[Tt]rue|[Ff]alse)$" ) {
133
134             @Override
135             Object parse(String value) {
136                 return Boolean.parseBoolean(value);
137             }
138
139         };
140
141         private final String regex;
142
143         TypeSupport(String regex) {
144             this.regex = regex;
145         }
146
147         abstract Object parse(String value);
148
149         static TypeSupport getType(String value) {
150             if (value != null) {
151                 for (TypeSupport typeSupport : TypeSupport.values()) {
152                     if (value.matches(typeSupport.regex)) {
153                         return typeSupport;
154                     }
155                 }
156             }
157             return null;
158         }
159
160         static void cast(Properties props) {
161             props.forEach((key, val) -> {
162                 if (String.class.isInstance(val)) {
163                     String value = (String) val;
164                     TypeSupport typeSupport = getType(value);
165                     if (typeSupport != null) {
166                         props.replace(key, typeSupport.parse(value));
167                     }
168                 }
169             });
170         }
171
172     }
173
174 }