KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > vladium > util > IProperties


1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2  *
3  * This program and the accompanying materials are made available under
4  * the terms of the Common Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
6  *
7  * $Id: IProperties.java,v 1.1.1.1.2.1 2004/07/08 10:52:10 vlad_r Exp $
8  */

9 package com.vladium.util;
10
11 import java.io.PrintStream JavaDoc;
12 import java.io.PrintWriter JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Enumeration JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Properties JavaDoc;
19 import java.util.Set JavaDoc;
20 import java.util.TreeSet JavaDoc;
21
22 // ----------------------------------------------------------------------------
23
/**
24  * @author Vlad Roubtsov, (C) 2003
25  */

26 public
27 interface IProperties
28 {
29     // public: ................................................................
30

31     /**
32      * An IMapper is a stateless hook for mapping a arbitrary property key
33      * to another (useful, for example, for property aliasing and defaulting).
34      * Each IMapper must be completely stateless and could be shared between
35      * multiple IProperties instances (and invoked from multiple concurrent threads).
36      */

37     interface IMapper
38     {
39         String JavaDoc getMappedKey (final String JavaDoc key);
40         
41     } // end of nested interface
42

43     
44     String JavaDoc getProperty (String JavaDoc key);
45     String JavaDoc getProperty (String JavaDoc key, String JavaDoc dflt);
46     boolean isOverridden (String JavaDoc key);
47     
48     IProperties copy ();
49     Iterator JavaDoc /* String */ properties ();
50     Properties JavaDoc toProperties ();
51     /**
52      * @param prefix [may not be null]
53      */

54     String JavaDoc [] toAppArgsForm (final String JavaDoc prefix);
55     boolean isEmpty ();
56     void list (PrintStream JavaDoc out);
57     void list (PrintWriter JavaDoc out);
58
59     String JavaDoc setProperty (String JavaDoc key, String JavaDoc value);
60     
61     
62     abstract class Factory
63     {
64         /**
65          * Creates an empty IProperties set with an optional property mapper.
66          *
67          * @param mapper [may be null]
68          * @return an empty property set [never null]
69          */

70         public static IProperties create (final IMapper mapper)
71         {
72             return new PropertiesImpl (null, mapper);
73         }
74         
75         /**
76          * Converts a java.util.Properties instance to an IProperties instance,
77          * with an optional property mapper. Note that 'properties' content is
78          * shallowly cloned, so the result can be mutated independently from
79          * the input.
80          *
81          * @param properties [may not be null]
82          * @param mapper [may be null]
83          * @return a property set based on 'properties' [never null]
84          */

85         public static IProperties wrap (final Properties JavaDoc properties, final IMapper mapper)
86         {
87             final HashMap JavaDoc map = new HashMap JavaDoc ();
88             
89             // always use propertyNames() for traversing java.util.Properties:
90

91             for (Enumeration JavaDoc names = properties.propertyNames (); names.hasMoreElements (); )
92             {
93                 final String JavaDoc n = (String JavaDoc) names.nextElement ();
94                 final String JavaDoc v = properties.getProperty (n);
95                 
96                 map.put (n, v);
97             }
98             
99             return new PropertiesImpl (map, mapper); // note: map is a defensive clone
100
}
101
102         /**
103          * Combines two property sets by creating a property set that chains 'overrides'
104          * to 'base' for property delegation. Note that 'overrides' are cloned
105          * defensively and so the result can be mutated independently of both inputs.
106          *
107          * @param overrides [may be null]
108          * @param base [may be null]
109          * @return [never null; an empty property set with a null mapper is created
110          * if both inputs are null]
111          */

112         public static IProperties combine (final IProperties overrides, final IProperties base)
113         {
114             final IProperties result = overrides != null
115                 ? overrides.copy ()
116                 : create (null);
117             
118             // [assertion: result != null]
119

120             ((PropertiesImpl) result).getLastProperties ().setDelegate ((PropertiesImpl) base);
121             
122             return result;
123         }
124         
125         /*
126          * Not MT-safe
127          */

128         private static final class PropertiesImpl implements IProperties, Cloneable JavaDoc
129         {
130             // ACCESSORS (IProperties):
131

132             public String JavaDoc getProperty (final String JavaDoc key)
133             {
134                 return getProperty (key, null);
135             }
136             
137             public String JavaDoc getProperty (final String JavaDoc key, final String JavaDoc dflt)
138             {
139                 String JavaDoc value = (String JavaDoc) m_valueMap.get (key);
140                 
141                 // first, try to delegate horizontally:
142
if ((value == null) && (m_mapper != null))
143                 {
144                     final String JavaDoc mappedKey = m_mapper.getMappedKey (key);
145                     
146                     if (mappedKey != null)
147                         value = (String JavaDoc) m_valueMap.get (mappedKey);
148                 }
149                 
150                 // next, try to delegate vertically:
151
if ((value == null) && (m_delegate != null))
152                 {
153                     value = m_delegate.getProperty (key, null);
154                 }
155                 
156                 return value != null ? value : dflt;
157             }
158             
159             public boolean isOverridden (final String JavaDoc key)
160             {
161                 return m_valueMap.containsKey (key);
162             }
163             
164             public IProperties copy ()
165             {
166                 final PropertiesImpl _clone;
167                 try
168                 {
169                     _clone = (PropertiesImpl) super.clone ();
170                 }
171                 catch (CloneNotSupportedException JavaDoc cnse)
172                 {
173                     throw new Error JavaDoc (cnse.toString ()); // never happens
174
}
175
176                 _clone.m_valueMap = (HashMap JavaDoc) m_valueMap.clone ();
177                 _clone.m_unmappedKeySet = null;
178                 
179                 // note: m_mapper field is not cloned by design (mappers are stateless/shareable)
180

181                 PropertiesImpl scan = _clone;
182                 for (PropertiesImpl delegate = m_delegate; delegate != null; delegate = delegate.m_delegate)
183                 {
184                     final PropertiesImpl _delegateClone;
185                     try
186                     {
187                         _delegateClone = (PropertiesImpl) delegate.clone ();
188                     }
189                     catch (CloneNotSupportedException JavaDoc cnse)
190                     {
191                         throw new Error JavaDoc (cnse.toString ()); // never happens
192
}
193                     
194                     // note that the value map needs to be cloned not only for the
195
// outermost IProperties set but for the inner ones as well
196
// (to prevent independent mutation in them from showing through)
197

198                     _delegateClone.m_valueMap = (HashMap JavaDoc) delegate.m_valueMap.clone ();
199                     _delegateClone.m_unmappedKeySet = null; // ensure that the last delegate will have this field reset
200

201                     scan.setDelegate (_delegateClone);
202                     scan = _delegateClone;
203                 }
204                 
205                 return _clone;
206             }
207             
208             public Iterator JavaDoc /* String */ properties ()
209             {
210                 return unmappedKeySet ().iterator ();
211             }
212             
213             public Properties JavaDoc toProperties ()
214             {
215                 final Properties JavaDoc result = new Properties JavaDoc ();
216                 
217                 for (Iterator JavaDoc i = properties (); i.hasNext (); )
218                 {
219                     final String JavaDoc n = (String JavaDoc) i.next ();
220                     final String JavaDoc v = getProperty (n);
221                     
222                     result.setProperty (n, v);
223                 }
224                 
225                 return result;
226             }
227             
228             public boolean isEmpty ()
229             {
230                 return m_valueMap.isEmpty () && ((m_delegate == null) || ((m_delegate != null) && m_delegate.isEmpty ()));
231             }
232             
233             public String JavaDoc [] toAppArgsForm (final String JavaDoc prefix)
234             {
235                 if (isEmpty ())
236                     return IConstants.EMPTY_STRING_ARRAY;
237                 else
238                 {
239                     if (prefix == null)
240                         throw new IllegalArgumentException JavaDoc ("null input: prefix");
241                     
242                     final List JavaDoc _result = new ArrayList JavaDoc ();
243                     for (Iterator JavaDoc names = properties (); names.hasNext (); )
244                     {
245                         final String JavaDoc name = (String JavaDoc) names.next ();
246                         final String JavaDoc value = getProperty (name, "");
247                         
248                         _result.add (prefix.concat (name).concat ("=").concat (value));
249                     }
250                     
251                     final String JavaDoc [] result = new String JavaDoc [_result.size ()];
252                     _result.toArray (result);
253                     
254                     return result;
255                 }
256             }
257
258             public void list (final PrintStream JavaDoc out)
259             {
260                 if (out != null)
261                 {
262                     for (Iterator JavaDoc i = properties (); i.hasNext (); )
263                     {
264                         final String JavaDoc n = (String JavaDoc) i.next ();
265                         final String JavaDoc v = getProperty (n);
266                         
267                         out.println (n + ":\t[" + v + "]");
268                     }
269                 }
270             }
271             
272             public void list (final PrintWriter JavaDoc out)
273             {
274                 if (out != null)
275                 {
276                     for (Iterator JavaDoc i = properties (); i.hasNext (); )
277                     {
278                         final String JavaDoc n = (String JavaDoc) i.next ();
279                         final String JavaDoc v = getProperty (n);
280                         
281                         out.println (n + ":\t[" + v + "]");
282                     }
283                 }
284             }
285             
286             // MUTATORS:
287

288             public String JavaDoc setProperty (final String JavaDoc key, final String JavaDoc value)
289             {
290                 if (value == null)
291                     throw new IllegalArgumentException JavaDoc ("null input: value");
292                 
293                 m_unmappedKeySet = null;
294                 
295                 return (String JavaDoc) m_valueMap.put (key, value);
296             }
297             
298             
299             PropertiesImpl (final HashMap JavaDoc values, final IMapper mapper)
300             {
301                 m_mapper = mapper;
302                 m_valueMap = values != null ? values : new HashMap JavaDoc ();
303                 
304                 m_delegate = null;
305             }
306             
307             
308             Set JavaDoc unmappedKeySet ()
309             {
310                 Set JavaDoc result = m_unmappedKeySet;
311                 if (result == null)
312                 {
313                     result = new TreeSet JavaDoc ();
314                     result.addAll (m_valueMap.keySet ());
315                     if (m_delegate != null)
316                         result.addAll (m_delegate.unmappedKeySet ());
317                     
318                     m_unmappedKeySet = result;
319                     return result;
320                 }
321                 
322                 return result;
323             }
324             
325             // ACCESSORS:
326

327             PropertiesImpl getLastProperties ()
328             {
329                 PropertiesImpl result = this;
330                 
331                 for (PropertiesImpl delegate = m_delegate; delegate != null; delegate = delegate.m_delegate)
332                 {
333                     // this does not detect all possible cycles:
334
if (delegate == this)
335                         throw new IllegalStateException JavaDoc ("cyclic delegation detected");
336                     
337                     result = delegate;
338                 }
339                 
340                 return result;
341             }
342             
343             // MUTATORS:
344

345             void setDelegate (final PropertiesImpl delegate)
346             {
347                 m_delegate = delegate;
348                 
349                 m_unmappedKeySet = null;
350             }
351             
352             
353             private final IMapper m_mapper;
354             private /*final*/ HashMap JavaDoc m_valueMap; // never null
355

356             private PropertiesImpl m_delegate;
357             private transient Set JavaDoc m_unmappedKeySet;
358             
359         } // end of nested class
360

361     } // end of nested class
362

363     // protected: .............................................................
364

365     // package: ...............................................................
366

367     // private: ...............................................................
368

369 } // end of class
370
// ----------------------------------------------------------------------------
Popular Tags