1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.healthmarketscience.jackcess.impl;
18
19 import java.io.IOException;
20 import java.time.LocalDateTime;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26
27 import com.healthmarketscience.jackcess.DataType;
28 import com.healthmarketscience.jackcess.PropertyMap;
29
30
31
32
33
34
35 public class PropertyMapImpl implements PropertyMap
36 {
37 private static final Map<String,PropDef> DEFAULT_TYPES =
38 new HashMap<String,PropDef>();
39
40 static {
41 DEFAULT_TYPES.put(ACCESS_VERSION_PROP, new PropDef(DataType.TEXT, false));
42 DEFAULT_TYPES.put(TITLE_PROP, new PropDef(DataType.TEXT, false));
43 DEFAULT_TYPES.put(AUTHOR_PROP, new PropDef(DataType.TEXT, false));
44 DEFAULT_TYPES.put(COMPANY_PROP, new PropDef(DataType.TEXT, false));
45
46 DEFAULT_TYPES.put(DEFAULT_VALUE_PROP, new PropDef(DataType.MEMO, true));
47 DEFAULT_TYPES.put(REQUIRED_PROP, new PropDef(DataType.BOOLEAN, true));
48 DEFAULT_TYPES.put(ALLOW_ZERO_LEN_PROP, new PropDef(DataType.BOOLEAN, true));
49 DEFAULT_TYPES.put(DECIMAL_PLACES_PROP, new PropDef(DataType.BYTE, true));
50 DEFAULT_TYPES.put(FORMAT_PROP, new PropDef(DataType.TEXT, true));
51 DEFAULT_TYPES.put(INPUT_MASK_PROP, new PropDef(DataType.TEXT, true));
52 DEFAULT_TYPES.put(CAPTION_PROP, new PropDef(DataType.MEMO, false));
53 DEFAULT_TYPES.put(VALIDATION_RULE_PROP, new PropDef(DataType.TEXT, true));
54 DEFAULT_TYPES.put(VALIDATION_TEXT_PROP, new PropDef(DataType.TEXT, true));
55 DEFAULT_TYPES.put(GUID_PROP, new PropDef(DataType.BINARY, true));
56 DEFAULT_TYPES.put(DESCRIPTION_PROP, new PropDef(DataType.MEMO, false));
57 DEFAULT_TYPES.put(RESULT_TYPE_PROP, new PropDef(DataType.BYTE, true));
58 DEFAULT_TYPES.put(EXPRESSION_PROP, new PropDef(DataType.MEMO, true));
59 DEFAULT_TYPES.put(DISPLAY_CONTROL_PROP, new PropDef(DataType.INT, false));
60 DEFAULT_TYPES.put(TEXT_FORMAT_PROP, new PropDef(DataType.BYTE, false));
61 DEFAULT_TYPES.put(IME_MODE_PROP, new PropDef(DataType.BYTE, false));
62 DEFAULT_TYPES.put(IME_SENTENCE_MODE_PROP, new PropDef(DataType.BYTE, false));
63 }
64
65 private final String _mapName;
66 private final short _mapType;
67 private final Map<String,Property> _props =
68 new LinkedHashMap<String,Property>();
69 private final PropertyMaps _owner;
70
71 public PropertyMapImpl(String name, short type, PropertyMaps owner) {
72 _mapName = name;
73 _mapType = type;
74 _owner = owner;
75 }
76
77 @Override
78 public String getName() {
79 return _mapName;
80 }
81
82 public short getType() {
83 return _mapType;
84 }
85
86 public PropertyMaps getOwner() {
87 return _owner;
88 }
89
90 @Override
91 public int getSize() {
92 return _props.size();
93 }
94
95 @Override
96 public boolean isEmpty() {
97 return _props.isEmpty();
98 }
99
100 @Override
101 public Property get(String name) {
102 return _props.get(DatabaseImpl.toLookupName(name));
103 }
104
105 @Override
106 public Object getValue(String name) {
107 return getValue(name, null);
108 }
109
110 @Override
111 public Object getValue(String name, Object defaultValue) {
112 Property prop = get(name);
113 Object value = defaultValue;
114 if((prop != null) && (prop.getValue() != null)) {
115 value = prop.getValue();
116 }
117 return value;
118 }
119
120 @Override
121 public PropertyImpl put(String name, Object value) {
122 return put(name, null, value, false);
123 }
124
125 @Override
126 public PropertyImpl put(String name, DataType type, Object value) {
127 return put(name, type, value, false);
128 }
129
130 @Override
131 public void putAll(Iterable<? extends Property> props) {
132 if(props == null) {
133 return;
134 }
135
136 for(Property prop : props) {
137 put(prop);
138 }
139 }
140
141 public PropertyImpl put(Property prop) {
142 return put(prop.getName(), prop.getType(), prop.getValue(), prop.isDdl());
143 }
144
145
146
147
148 @Override
149 public PropertyImpl put(String name, DataType type, Object value,
150 boolean isDdl) {
151 PropertyImpl prop = (PropertyImpl)createProperty(name, type, value, isDdl);
152 _props.put(DatabaseImpl.toLookupName(name), prop);
153 return prop;
154 }
155
156 @Override
157 public PropertyImpl remove(String name) {
158 return (PropertyImpl)_props.remove(DatabaseImpl.toLookupName(name));
159 }
160
161 @Override
162 public Iterator<Property> iterator() {
163 return _props.values().iterator();
164 }
165
166 @Override
167 public void save() throws IOException {
168 getOwner().save();
169 }
170
171 @Override
172 public String toString() {
173 return toString(this);
174 }
175
176 public static String toString(PropertyMap map) {
177 StringBuilder sb = new StringBuilder();
178 sb.append(PropertyMaps.DEFAULT_NAME.equals(map.getName()) ?
179 "<DEFAULT>" : map.getName())
180 .append(" {");
181 for(Iterator<Property> iter = map.iterator(); iter.hasNext(); ) {
182 sb.append(iter.next());
183 if(iter.hasNext()) {
184 sb.append(",");
185 }
186 }
187 sb.append("}");
188 return sb.toString();
189 }
190
191 public static Property createProperty(String name, DataType type, Object value) {
192 return createProperty(name, type, value, false);
193 }
194
195 public static Property createProperty(String name, DataType type,
196 Object value, boolean isDdl) {
197
198 PropDef pd = DEFAULT_TYPES.get(name);
199
200 if(value instanceof PropertyMap.EnumValue) {
201
202 value = ((PropertyMap.EnumValue)value).getValue();
203 }
204
205 if(pd != null) {
206
207 type = ((type == null) ? pd._type : type);
208 isDdl |= pd._isDdl;
209 } else if(type == null) {
210
211 if(value instanceof String) {
212 type = DataType.TEXT;
213 } else if(value instanceof Boolean) {
214 type = DataType.BOOLEAN;
215 } else if(value instanceof Byte) {
216 type = DataType.BYTE;
217 } else if(value instanceof Short) {
218 type = DataType.INT;
219 } else if(value instanceof Integer) {
220 type = DataType.LONG;
221 } else if(value instanceof Float) {
222 type = DataType.FLOAT;
223 } else if(value instanceof Double) {
224 type = DataType.DOUBLE;
225 } else if((value instanceof Date) || (value instanceof LocalDateTime)) {
226 type = DataType.SHORT_DATE_TIME;
227 } else if(value instanceof byte[]) {
228 type = DataType.OLE;
229 } else if(value instanceof Long) {
230 type = DataType.BIG_INT;
231 } else {
232 throw new IllegalArgumentException(
233 "Could not determine type for property " + name +
234 " with value " + value);
235 }
236 }
237
238 return new PropertyImpl(name, type, value, isDdl);
239 }
240
241
242
243
244 static final class PropertyImpl implements PropertyMap.Property
245 {
246 private final String _name;
247 private final DataType _type;
248 private final boolean _ddl;
249 private Object _value;
250
251 private PropertyImpl(String name, DataType type, Object value,
252 boolean ddl) {
253 _name = name;
254 _type = type;
255 _ddl = ddl;
256 _value = value;
257 }
258
259 @Override
260 public String getName() {
261 return _name;
262 }
263
264 @Override
265 public DataType getType() {
266 return _type;
267 }
268
269 @Override
270 public Object getValue() {
271 return _value;
272 }
273
274 @Override
275 public void setValue(Object newValue) {
276 _value = newValue;
277 }
278
279 @Override
280 public boolean isDdl() {
281 return _ddl;
282 }
283
284 @Override
285 public String toString() {
286 Object val = getValue();
287 if(val instanceof byte[]) {
288 val = ByteUtil.toHexString((byte[])val);
289 }
290 return getName() + "[" + getType() + (_ddl ? ":ddl" : "") + "]=" + val;
291 }
292 }
293
294
295
296
297 private static final class PropDef
298 {
299 private final DataType _type;
300 private final boolean _isDdl;
301
302 private PropDef(DataType type, boolean isDdl) {
303 _type = type;
304 _isDdl = isDdl;
305 }
306 }
307 }