1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package com.commsen.apropos.core;
20
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.LinkedHashMap;
24 import java.util.LinkedList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Properties;
28
29 import org.apache.commons.lang.StringUtils;
30
31 /***
32 * This class represents a package of properties. In APropOS a package is simply a container of
33 * {@link Property} objects. A package has name and may also have description, parent and child
34 * packages.
35 *
36 * @author Milen Dyankov
37 *
38 */
39
40 public class PropertyPackage implements Cloneable {
41
42 /***
43 * the name of the package
44 */
45 private String name;
46
47 /***
48 * the description of the package
49 */
50 private String description;
51
52 /***
53 * reference to the parent
54 */
55 private PropertyPackage parent = null;
56
57 /***
58 * properties
59 */
60 private Map<String, Property> properties = new LinkedHashMap<String, Property>();
61
62 /***
63 * list of child packages
64 */
65 private List<PropertyPackage> children = new LinkedList<PropertyPackage>();
66
67
68 /***
69 * Constructs new package
70 *
71 * @param name the name, this is required field
72 * @param description the description
73 * @param parent the parent package, if not provided it will become first level package
74 * @throws IllegalArgumentException if name is <code>null</code> or blank
75 */
76 public PropertyPackage(String name, String description, PropertyPackage parent) {
77 if (StringUtils.isBlank(name)) throw new IllegalArgumentException("name can not be null");
78 this.name = name.trim();
79 this.description = description;
80 if (parent != null) {
81 this.parent = parent;
82 parent.children.add(this);
83 }
84 }
85
86
87 /***
88 * Constructs new first level package (without parent)
89 *
90 * @param name the name, this is required field
91 * @param description the description
92 */
93 public PropertyPackage(String name, String description) {
94 this(name, description, null);
95 }
96
97
98 /***
99 * Constructs new package
100 *
101 * @param name the name, this is required field
102 * @param parent the parent package, if not provided it will become first level package
103 */
104 public PropertyPackage(String name, PropertyPackage parent) {
105 this(name, null, parent);
106 }
107
108
109 /***
110 * Constructs new package
111 *
112 * @param name the name, this is required field
113 */
114 public PropertyPackage(String name) {
115 this(name, null, null);
116 }
117
118
119 /***
120 * {@inheritDoc}
121 */
122 @Override
123 public Object clone() throws CloneNotSupportedException {
124 PropertyPackage result = (PropertyPackage) super.clone();
125 result.properties = new LinkedHashMap<String, Property>();
126 if (!properties.isEmpty()) {
127 for (Property property : properties.values()) {
128 result.properties.put(property.getName(), (Property) property.clone());
129 }
130 }
131 return result;
132 }
133
134
135 /***
136 * Adds new property to this package.
137 *
138 * @param property the {@link Property} to be added. This is a required parameter
139 * @return reference do the added property
140 * @throws PropertiesException if property with such name already exists
141 * @throws IllegalArgumentException if <code>property</code> is null
142 */
143 public Property addProperty(Property property) throws PropertiesException {
144 if (property == null) throw new IllegalArgumentException("property can not be null");
145 if (properties.containsKey(property.getName())) throw new PropertiesException("Property called " + property.getName() + " already exists!");
146 return properties.put(property.getName(), property);
147 }
148
149
150 /***
151 * Updates a property in this package.
152 *
153 * @param property the {@link Property} to be updated. This is a required parameter
154 * @return reference do the added property
155 * @throws PropertiesException if no such property exists
156 * @throws IllegalArgumentException if <code>property</code> is null
157 */
158 public Property updateProperty(Property property) throws PropertiesException {
159 if (property == null) throw new IllegalArgumentException("property can not be null");
160 if (!properties.containsKey(property.getName())) throw new PropertiesException("Property called " + property.getName() + " does not exists!");
161 return properties.put(property.getName(), property);
162 }
163
164
165 /***
166 * Updates a property called <code>oldName</code> in this package with values from
167 * <code>property</code>. If <code>oldName</code> is null this method behaves exactly like
168 * {@link #updateProperty(Property)}
169 *
170 * @param oldName the name of the property to be updated
171 * @param property the property to get values from
172 * @return reference do the added property
173 * @throws PropertiesException if no such property exists
174 * @throws IllegalArgumentException if <code>property</code> is null
175 */
176 public Property updateProperty(String oldName, Property property) throws PropertiesException {
177 if (StringUtils.isBlank(oldName)) return updateProperty(property);
178 if (property == null) throw new IllegalArgumentException("property can not be null");
179 if (!properties.containsKey(oldName)) throw new PropertiesException("Property called " + oldName + " does not exists!");
180 if (!oldName.equals(property.getName())) {
181 properties.remove(oldName);
182 }
183 return properties.put(property.getName(), property);
184 }
185
186
187 /***
188 * Removes property from this package
189 *
190 * @param property the property to be removed
191 * @return reference to removed property
192 */
193 public Property removeProperty(Property property) {
194 if (property == null) throw new IllegalArgumentException("property can not be null");
195 return properties.remove(property.getName());
196 }
197
198
199 /***
200 * Removes property called <code>propertyName</code> from this package
201 *
202 * @param propertyName the name of the property to be removed
203 * @return reference to removed property
204 */
205 public Property removeProperty(String propertyName) {
206 if (propertyName == null) throw new IllegalArgumentException("property name can not be null or empty string");
207 return properties.remove(propertyName);
208 }
209
210
211 /***
212 * Reads external {@link Properties} and adds them all to this package.
213 *
214 * @param externalProperties the external properties to be added
215 * @param overwrite boolean flag indicating whether to overwrite existing properties
216 * @throws IllegalArgumentException if <code>externalProperties</code> is null
217 */
218 public void importProperties(Properties externalProperties, boolean overwrite) {
219 if (externalProperties == null) throw new IllegalArgumentException("properties can not be null");
220 for (Object key : externalProperties.keySet()) {
221 String propertyName = (String) key;
222 if (!overwrite && this.properties.containsKey(propertyName)) continue;
223 try {
224 this.properties.put(propertyName, new Property(propertyName, externalProperties.getProperty(propertyName), null, null));
225 } catch (PropertiesException e) {
226
227
228
229
230 throw new InternalError(e.getMessage());
231 }
232 }
233 }
234
235
236 /***
237 * Converts this package to {@link Properties} object. The result object contains all properties
238 * from all parents as returned by {@link #getAllProperties()}.
239 *
240 * @return {@link Properties} object
241 */
242 public Properties asProperties() {
243 Properties result = new Properties();
244 for (Property property : getAllProperties().values()) {
245 result.setProperty(property.getName(), property.getValue());
246 }
247 return result;
248 }
249
250
251 /***
252 * Returns a map of all properties in this package which overwrite same properties from parent
253 * packages.
254 *
255 * @return the properties a map of all properties in this package which overwrite same
256 * properties from parent packages.
257 */
258 public Map<String, Property> getOverwritenProperties() {
259 Map<String, Property> parentProperties = new HashMap<String, Property>();
260 if (parent != null) parentProperties.putAll(parent.getAllProperties());
261
262 Map<String, Property> result = new HashMap<String, Property>();
263 for (String propertyName : properties.keySet()) {
264 if (parentProperties.containsKey(propertyName)) {
265 result.put(propertyName, parentProperties.get(propertyName));
266 }
267 }
268 return result;
269 }
270
271
272 /***
273 * Returns a map of all properties from this package and all parent packages.
274 *
275 * @return a map of all properties from this package and all parent packages.
276 */
277 public Map<String, Property> getAllProperties() {
278 Map<String, Property> result = new HashMap<String, Property>();
279 if (parent != null) result.putAll(parent.getAllProperties());
280 result.putAll(properties);
281 return result;
282 }
283
284
285 /***
286 * Checks if <code>propertyPackage</code> is a child package of this package.
287 *
288 * @param propertyPackage 0 the package to be checked
289 * @return <code>true</code> if <code>propertyPackage</code> is a child package of this
290 * package, <code>false</code> otherwise.
291 */
292 public boolean containsChild(PropertyPackage propertyPackage) {
293 if (propertyPackage == null) return false;
294 if (children.contains(propertyPackage)) return true;
295 for (PropertyPackage child : children) {
296 if (child.containsChild(propertyPackage)) return true;
297 }
298 return false;
299 }
300
301
302 /***
303 * @return the properties
304 */
305 public Map<String, Property> getProperties() {
306 return properties;
307 }
308
309
310 /***
311 * @return the parent
312 */
313 public PropertyPackage getParent() {
314 return this.parent;
315 }
316
317
318 /***
319 * @param parent the parent to set
320 * @throws PropertiesException
321 */
322 public void setParent(PropertyPackage parent) throws PropertiesException {
323 if (this.parent == parent) return;
324 if (containsChild(parent)) {
325 throw new PropertiesException("Package " + parent.getName() + " is child of " + name + " and can not be set as it's parent!");
326 }
327 if (this.parent != null) {
328 this.parent.children.remove(this);
329 }
330 this.parent = parent;
331 if (this.parent != null) {
332 this.parent.children.add(this);
333 }
334 }
335
336
337 /***
338 * @return the description
339 */
340 public String getDescription() {
341 return this.description;
342 }
343
344
345 /***
346 * @param description the description to set
347 */
348 public void setDescription(String description) {
349 this.description = description;
350 }
351
352
353 /***
354 * @return the name
355 */
356 public String getName() {
357 return this.name;
358 }
359
360
361 /***
362 * @return the children
363 */
364 public List<PropertyPackage> getChildren() {
365 return Collections.unmodifiableList(this.children);
366 }
367
368 }