View Javadoc

1   package org.apache.velocity.tools.config;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.List;
25  import java.util.SortedSet;
26  import java.util.TreeSet;
27  import org.apache.velocity.tools.ToolboxFactory;
28  
29  /**
30   * <p>This class serves to define configuration info for a {@link ToolboxFactory}.
31   * It contains the {@link ToolboxConfiguration}s for the factory as well
32   * as any {@link Data} which is to be made available in the application scope
33   * by the factory and any {@link Property}s which you intend to be available
34   * to <strong>all</strong> tools managed by the factory, regardless of
35   * toolbox or scope.
36   * </p><p>
37   * Most users will not find themselves directly using the API of this class,
38   * as its subclasses generally provide much simpler means of inputting
39   * the actual configuration info whether from XML, Java or a Properties files.
40   * </p><p>
41   * When combining any {@link Configuration}s via the various
42   * {@link #addConfiguration} methods in each class, it is
43   * <strong>essential</strong> to remember that subsequent configurations
44   * always override previous ones.  This is a "last entry wins" approach
45   * to configuration!
46   * </p><p>
47   * For debugging, this class tracks its "sources", keeping a chronological list
48   * of all sources for configuration data.  When you add configuration info
49   * to this class via {@link #addConfiguration}, the source lists from those
50   * {@link FactoryConfiguration}s is appended to this instance's list.  The
51   * initial item in this list will typically be the name of the FactoryConfiguration
52   * class (or subclass) along with a caller-provided string identifying where
53   * this instance was created.  This aids greatly in debugging combined, complex
54   * configurations.  You may add further sources at any time via
55   * {@link #addSource}.
56   * </p><p>
57   * The {@link #toString()} method of this class provides a complete and
58   * well-formatted listing of the configuration info contained within this
59   * instance and is also very useful for debugging.
60   * </p>
61   *
62   * @author Nathan Bubna
63   * @version $Id: FactoryConfiguration.java 511959 2007-02-26 19:24:39Z nbubna $
64   */
65  public class FactoryConfiguration
66      extends CompoundConfiguration<ToolboxConfiguration>
67  {
68      private final SortedSet<Data> data = new TreeSet<Data>();
69      private final List<String> sources = new ArrayList<String>();
70  
71      public FactoryConfiguration()
72      {
73          this("");
74      }
75      
76      /**
77       * Creates a new instance with the specified source name
78       * combined with this class's name as the initial source.
79       */
80      public FactoryConfiguration(String source)
81      {
82          this(FactoryConfiguration.class, source);
83      }
84  
85      /**
86       * Allows subclasses to construct an instance that uses their classname.
87       */
88      protected FactoryConfiguration(Class clazz, String source)
89      {
90          addSource(clazz.getName()+"("+source+")");
91      }
92  
93      /**
94       * Returns the original source of this particular instance.
95       */
96      public String getSource()
97      {
98          return this.sources.get(0);
99      }
100 
101     /**
102      * Sets the name of the original source of this particular instance.
103      * This does not affect subsequently added sources.
104      */
105     public void setSource(String source)
106     {
107         this.sources.set(0, source);
108     }
109 
110     /**
111      * Returns the list of sources for this configuration info in
112      * order starting from the source name given to this instance
113      * (if any) and going to the most recently added source.
114      */
115     public List<String> getSources()
116     {
117         return this.sources;
118     }
119 
120     public void addSource(String source)
121     {
122         this.sources.add(source);
123     }
124 
125     public void addData(Data newDatum)
126     {
127         // check if we already have a matching datum
128         Data datum = getData(newDatum);
129         if (datum != null)
130         {
131             // newer overrides older, so...
132             // remove the old datum
133             removeData(datum);
134         }
135         // add the new datum
136         data.add(newDatum);
137     }
138 
139     public boolean removeData(Data datum)
140     {
141         return data.remove(datum);
142     }
143 
144     public Data getData(String key)
145     {
146         // create an example to search with
147         Data findme = new Data();
148         findme.setKey(key);
149         return getData(findme);
150     }
151 
152     public Data getData(Data findme)
153     {
154         for (Data datum : data)
155         {
156             if (datum.equals(findme))
157             {
158                 return datum;
159             }
160         }
161         return null;
162     }
163 
164     public boolean hasData()
165     {
166         return !data.isEmpty();
167     }
168 
169     public SortedSet<Data> getData()
170     {
171         return data;
172     }
173 
174     public void setData(Collection<Data> data)
175     {
176         for (Data datum : data)
177         {
178             addData(datum);
179         }
180     }
181 
182     public void addToolbox(ToolboxConfiguration toolbox)
183     {
184         addChild(toolbox);
185     }
186 
187     public void removeToolbox(ToolboxConfiguration toolbox)
188     {
189         removeChild(toolbox);
190     }
191 
192     public ToolboxConfiguration getToolbox(String scope)
193     {
194         for (ToolboxConfiguration toolbox : getToolboxes())
195         {
196             if (scope.equals(toolbox.getScope()))
197             {
198                 return toolbox;
199             }
200         }
201         return null;
202     }
203 
204     public Collection<ToolboxConfiguration> getToolboxes()
205     {
206         return getChildren();
207     }
208 
209     public void setToolboxes(Collection<ToolboxConfiguration> toolboxes)
210     {
211         setChildren(toolboxes);
212     }
213 
214     public void addConfiguration(FactoryConfiguration config)
215     {
216         // add config's Data to our own
217         setData(config.getData());
218 
219         // add config's sources to our own
220         for (String source : config.getSources())
221         {
222             addSource(source);
223         }
224 
225         // pass to CompoundConfiguration's to add properties
226         super.addConfiguration(config);
227     }
228 
229     @Override
230     public void validate()
231     {
232         super.validate();
233 
234         for (Data datum : data)
235         {
236             datum.validate();
237         }
238     }
239 
240     /**
241      * This will consider the object equal if it is a FactoryConfiguration
242      * and whose {@link #toString(boolean)} method, when passed <code>false</code>,
243      * returns a String equal to that returned by a call to toString(false) on this
244      * instance.  {@link #toString(boolean)} is used since that returns a String
245      * encompassing all relevant info about the configuration except for the
246      * source information.  In other words, two FactoryConfigurations are considered
247      * equal if they have the same data, properties and toolboxes in String form.
248      */
249     @Override
250     public boolean equals(Object o)
251     {
252         if (o instanceof FactoryConfiguration)
253         {
254             FactoryConfiguration that = (FactoryConfiguration)o;
255             return that.toString(false).equals(this.toString(false));
256         }
257         return false;
258     }
259 
260     @Override
261     public int hashCode()
262     {
263         return toString(false).hashCode();
264     }
265 
266     @Override
267     public String toString()
268     {
269         return toString(true);
270     }
271 
272     public String toString(boolean includeSources)
273     {
274         StringBuilder out = new StringBuilder();
275         out.append("\nFactoryConfiguration from ");
276         if (includeSources)
277         {
278             out.append(getSources().size());
279             out.append(" sources ");
280         }
281         appendProperties(out);
282         if (hasData())
283         {
284             out.append("including ");
285             out.append(data.size());
286             out.append(" data");
287         }
288         if (getToolboxes().isEmpty())
289         {
290             out.append("\n ");
291         }
292         else
293         {
294             appendChildren(out, "toolboxes: \n ", "\n ");
295         }
296         if (hasData())
297         {
298             for (Data datum : data)
299             {
300                 out.append(datum);
301                 out.append("\n ");
302             }
303         }
304         if (includeSources)
305         {
306             int count = 0;
307             for (String source : getSources())
308             {
309                 out.append("\n Source ");
310                 out.append(count++);
311                 out.append(": ");
312                 out.append(source);
313             }
314             out.append("\n");
315         }
316         return out.toString();
317     }
318 
319 
320     public ToolboxFactory createFactory()
321     {
322         ToolboxFactory factory = new ToolboxFactory();
323         factory.configure(this);
324         return factory;
325     }
326 
327 }