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