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,DataType> DEFAULT_TYPES =
37      new HashMap<String,DataType>();
38  
39    static {
40      DEFAULT_TYPES.put(ACCESS_VERSION_PROP, DataType.TEXT);
41      DEFAULT_TYPES.put(TITLE_PROP, DataType.TEXT);
42      DEFAULT_TYPES.put(AUTHOR_PROP, DataType.TEXT);
43      DEFAULT_TYPES.put(COMPANY_PROP, DataType.TEXT);
44  
45      DEFAULT_TYPES.put(DEFAULT_VALUE_PROP, DataType.MEMO);
46      DEFAULT_TYPES.put(REQUIRED_PROP, DataType.BOOLEAN);
47      DEFAULT_TYPES.put(ALLOW_ZERO_LEN_PROP, DataType.BOOLEAN);
48      DEFAULT_TYPES.put(DECIMAL_PLACES_PROP, DataType.BYTE);
49      DEFAULT_TYPES.put(FORMAT_PROP, DataType.TEXT);
50      DEFAULT_TYPES.put(INPUT_MASK_PROP, DataType.TEXT);
51      DEFAULT_TYPES.put(CAPTION_PROP, DataType.MEMO);
52      DEFAULT_TYPES.put(VALIDATION_RULE_PROP, DataType.TEXT);
53      DEFAULT_TYPES.put(VALIDATION_TEXT_PROP, DataType.TEXT);
54      DEFAULT_TYPES.put(GUID_PROP, DataType.BINARY);
55      DEFAULT_TYPES.put(DESCRIPTION_PROP, DataType.MEMO);
56      DEFAULT_TYPES.put(RESULT_TYPE_PROP, DataType.BYTE);
57      DEFAULT_TYPES.put(EXPRESSION_PROP, DataType.MEMO);
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, (byte)0, value);
111   }
112 
113   public PropertyImpl put(String name, DataType type, Object value) {
114     return put(name, type, (byte)0, value);
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     byte flag = 0;
129     if(prop instanceof PropertyImpl) {
130       flag = ((PropertyImpl)prop).getFlag();
131     }
132     return put(prop.getName(), prop.getType(), flag, prop.getValue());
133   }
134 
135   /**
136    * Puts a property into this map with the given information.
137    */
138   public PropertyImpl put(String name, DataType type, byte flag, Object value) {
139     PropertyImpl prop = (PropertyImpl)createProperty(name, type, flag, value);
140     _props.put(DatabaseImpl.toLookupName(name), prop);
141     return prop;
142   }
143 
144   public PropertyImpl remove(String name) {
145     return (PropertyImpl)_props.remove(DatabaseImpl.toLookupName(name));
146   }
147 
148   public Iterator<Property> iterator() {
149     return _props.values().iterator();
150   }
151 
152   public void save() throws IOException {
153     getOwner().save();
154   }
155 
156   @Override
157   public String toString() {
158     return toString(this);
159   }      
160 
161   public static String toString(PropertyMap map) {
162     StringBuilder sb = new StringBuilder();
163     sb.append(PropertyMaps.DEFAULT_NAME.equals(map.getName()) ?
164               "<DEFAULT>" : map.getName())
165       .append(" {");
166     for(Iterator<Property> iter = map.iterator(); iter.hasNext(); ) {
167       sb.append(iter.next());
168       if(iter.hasNext()) {
169         sb.append(",");
170       }
171     }
172     sb.append("}");
173     return sb.toString();
174   }
175 
176   public static Property createProperty(String name, DataType type, Object value) {
177     return createProperty(name, type, (byte)0, value);
178   }
179   
180   public static Property createProperty(String name, DataType type, byte flag,
181                                         Object value) {
182     if(type == null) {
183       
184       // attempt to get the default type for this property
185       type = DEFAULT_TYPES.get(name);
186 
187       if(type == null) {
188         // choose the type based on the value
189         if(value instanceof String) {
190           type = DataType.TEXT;
191         } else if(value instanceof Boolean) {
192           type = DataType.BOOLEAN;
193         } else if(value instanceof Byte) {
194           type = DataType.BYTE;
195         } else if(value instanceof Short) {
196           type = DataType.INT;
197         } else if(value instanceof Integer) {
198           type = DataType.LONG;
199         } else if(value instanceof Float) {
200           type = DataType.FLOAT;
201         } else if(value instanceof Double) {
202           type = DataType.DOUBLE;
203         } else if(value instanceof Date) {
204           type = DataType.SHORT_DATE_TIME;
205         } else if(value instanceof byte[]) {
206           type = DataType.OLE;
207         } else {
208           throw new IllegalArgumentException(
209               "Could not determine type for property " + name +
210               " with value " + value);
211         }
212       }
213     }
214     
215     return new PropertyImpl(name, type, flag, value);
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 byte _flag;
226     private Object _value;
227 
228     private PropertyImpl(String name, DataType type, byte flag, Object value) {
229       _name = name;
230       _type = type;
231       _flag = flag;
232       _value = value;
233     }
234 
235     public String getName() {
236       return _name;
237     }
238 
239     public DataType getType() {
240       return _type;
241     }
242 
243     public Object getValue() {
244       return _value;
245     }
246 
247     public void setValue(Object newValue) {
248       _value = newValue;
249     }
250 
251     public byte getFlag() {
252       return _flag;
253     }
254 
255     @Override
256     public String toString() {
257       Object val = getValue();
258       if(val instanceof byte[]) {
259         val = ByteUtil.toHexString((byte[])val);
260       }
261       return getName() + "[" + getType() + ":" + _flag + "]=" + val;
262     }
263   }
264 
265 }