View Javadoc

1   package org.apache.torque.generator.configuration;
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.HashSet;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.torque.generator.configuration.UnitDescriptor.Packaging;
32  import org.apache.torque.generator.configuration.controller.ControlConfiguration;
33  import org.apache.torque.generator.configuration.controller.ControlConfigurationXmlParser;
34  import org.apache.torque.generator.configuration.controller.Output;
35  import org.apache.torque.generator.configuration.option.OptionsConfiguration;
36  import org.apache.torque.generator.configuration.outlet.OutletConfiguration;
37  import org.apache.torque.generator.configuration.outlet.OutletConfigurationXmlParser;
38  import org.apache.torque.generator.configuration.source.EntityReferences;
39  import org.apache.torque.generator.option.Option;
40  import org.apache.torque.generator.option.Options;
41  import org.apache.torque.generator.outlet.Outlet;
42  import org.apache.torque.generator.qname.QualifiedName;
43  
44  /**
45   * Reads the configuration of a unit of generation.
46   */
47  class UnitConfigurationReader
48  {
49      /**
50       * The logger.
51       */
52      private static Log log = LogFactory.getLog(UnitConfigurationReader.class);
53  
54      /**
55       * Reads the configuration for a unit of generation.
56       * @param unitDescriptor the descriptor of the generation unit, not null.
57       * @param configurationHandlers the available configuration handlers,
58       *        not null.
59       *
60       * @return the configuration of the unit of generation.
61       * @throws ConfigurationException if the configuration is incorrect
62       *         or cannot be read.
63       * @throws NullPointerException if the unitDescriptor or
64       *         configurationHandlers is null.
65       * @throws IllegalArgumentException if a reader is the wrong type of reader
66       *         for the given configuration type.
67       */
68      public UnitConfiguration read(
69              UnitDescriptor unitDescriptor,
70              ConfigurationHandlers configurationHandlers)
71          throws ConfigurationException
72      {
73          if (unitDescriptor == null)
74          {
75              throw new NullPointerException("unitDescriptor must not be null");
76          }
77          if (configurationHandlers == null)
78          {
79              throw new NullPointerException(
80                      "configurationHandlers must not be null");
81          }
82  
83          if (log.isDebugEnabled())
84          {
85              log.debug("Start reading unitConfiguration for unit "
86                      + getUnitDisplayName(unitDescriptor));
87          }
88  
89          UnitConfiguration unitConfiguration = new UnitConfiguration();
90          unitConfiguration.setConfigurationHandlers(
91                  configurationHandlers);
92          unitConfiguration.setOutputDirectoryMap(
93                  unitDescriptor.getProjectPaths().getOutputDirectoryMap());
94          unitConfiguration.setWorkDirectory(
95                  unitDescriptor.getProjectPaths().getWorkDirectory());
96          unitConfiguration.setOverrideSourceProvider(
97                  unitDescriptor.getOverrideSourceProvider());
98  
99          ConfigurationProvider configurationProvider
100             = createConfigurationProvider(unitDescriptor);
101         readControlConfiguration(
102                 unitConfiguration,
103                 unitDescriptor,
104                 configurationHandlers,
105                 configurationProvider);
106 
107         {
108             if (log.isDebugEnabled())
109             {
110                 log.debug("Start reading outlet configuration");
111             }
112             OutletConfiguration outletConfiguration
113                     = new OutletConfigurationXmlParser()
114                         .readOutletConfiguration(
115                                 configurationProvider,
116                                 unitDescriptor.getProjectPaths(),
117                                 configurationHandlers);
118             unitConfiguration.setOutletConfiguration(outletConfiguration);
119         }
120 
121         if (log.isDebugEnabled())
122         {
123             log.debug("Sucessfully read unitConfiguration for unit "
124                     + getUnitDisplayName(unitDescriptor));
125         }
126 
127 
128         if (unitDescriptor.getInheritsFrom() == null)
129         {
130             OutletConfiguration outletConfiguration
131                     = unitConfiguration.getOutletConfiguration();
132             outletConfiguration.resolveMergepointMappings();
133             return unitConfiguration;
134         }
135         UnitConfiguration inherited = read(
136                 unitDescriptor.getInheritsFrom(),
137                 configurationHandlers);
138 
139         // Loglevel of inherited may have changed during reading.
140         // Restore this loglevel.
141         unitConfiguration.getLoglevel().apply();
142 
143         mergeInheritedOutletConfiguration(unitConfiguration, inherited);
144         mergeInheritedOptionConfiguration(unitConfiguration, inherited);
145         mergeInheritedOutputFiles(unitConfiguration, inherited);
146         mergeInheritedEntityRefernces(unitConfiguration, inherited);
147         // target directory cannot be null and thus the current target directory
148         // always overrides the inherited target directory.
149 
150         return unitConfiguration;
151     }
152 
153     /**
154      * Merges the inherited output files with the output files
155      * of the current unit configuration.
156      *
157      * @param unitConfiguration the current unit configuration
158      * @param inheritedConfiguration the inherited unit configuration
159      *        which option configuration should be merged.
160      */
161     private void mergeInheritedOutputFiles(
162             UnitConfiguration unitConfiguration,
163             UnitConfiguration inheritedConfiguration)
164     {
165         List<Output> outputFiles = new ArrayList<Output>();
166         // inherited Files are generated first.
167         Set<QualifiedName> qualifiedNames = new HashSet<QualifiedName>();
168         for (Output output : inheritedConfiguration.getOutputList())
169         {
170             outputFiles.add(output);
171             qualifiedNames.add(output.getName());
172         }
173         for (Output output : unitConfiguration.getOutputList())
174         {
175             if (qualifiedNames.contains(output.getName()))
176             {
177                 Iterator<Output> addedOutputIt = outputFiles.iterator();
178                 while (addedOutputIt.hasNext())
179                 {
180                     if (addedOutputIt.next().getName().equals(output.getName()))
181                     {
182                         addedOutputIt.remove();
183                         log.info("Output with name " + output.getName()
184                                 + " is overridden in child and is replaced.");
185                         break;
186                     }
187                 }
188             }
189             outputFiles.add(output);
190         }
191         unitConfiguration.setOutputList(outputFiles);
192     }
193 
194     /**
195      * Merges the inherited entity references with the entity references
196      * of the current unit configuration.
197      *
198      * @param unitConfiguration the current unit configuration
199      * @param inheritedConfiguration the inherited unit configuration
200      *        which entity references should be merged.
201      */
202     private void mergeInheritedEntityRefernces(
203             UnitConfiguration unitConfiguration,
204             UnitConfiguration inheritedConfiguration)
205     {
206         EntityReferences entityReferences
207                 = unitConfiguration.getEntityReferences();
208         Map<String, byte[]> inheritedReferences
209                 = inheritedConfiguration.getEntityReferences()
210                     .getEntityReferences();
211         for (Map.Entry<String, byte[]> inheritedReference
212                 : inheritedReferences.entrySet())
213         {
214             String systemId = inheritedReference.getKey();
215             if (!entityReferences.containsSystemId(systemId))
216             {
217                 entityReferences.addEntityReference(
218                         systemId,
219                         inheritedReference.getValue());
220                 log.debug("entityReferences with system id "
221                         + systemId
222                         + " is inherited from the parent.");
223             }
224             else
225             {
226                 log.debug("entityReferences with system id "
227                         + systemId
228                         + " is overidden in the child.");
229             }
230         }
231     }
232 
233     /**
234      * Merges an inherited option configuration into the option
235      * configuration of the current unit configuration.
236      *
237      * @param unitConfiguration the current unit configuration
238      * @param inheritedConfiguration the inherited unit configuration
239      *        which option configuration should be merged.
240      */
241     private void mergeInheritedOptionConfiguration(
242             UnitConfiguration unitConfiguration,
243             UnitConfiguration inheritedConfiguration)
244     {
245         Options options = unitConfiguration.getOptions();
246         Options inheritedOptions = inheritedConfiguration.getOptions();
247         for (Map.Entry<QualifiedName, Option> entry
248             : inheritedOptions.getGlobalScope().entrySet())
249         {
250             QualifiedName optionName = entry.getKey();
251             Option option = entry.getValue();
252             if (!options.getGlobalScope().containsKey(optionName))
253             {
254                 options.setGlobalOption(option);
255             }
256         }
257     }
258 
259     /**
260      * Merges an inherited outlet configuration into the outlet
261      * configuration of the current unit configuration.
262      *
263      * @param unitConfiguration the current unit configuration
264      * @param inheritedConfiguration the inherited unit configuration
265      *        which outlets should be merged.
266      *
267      * @throws ConfigurationException will not normally happen.
268      */
269     private void mergeInheritedOutletConfiguration(
270                 UnitConfiguration unitConfiguration,
271                 UnitConfiguration inheritedConfiguration)
272             throws ConfigurationException
273     {
274         OutletConfiguration outletConfiguration
275             = unitConfiguration.getOutletConfiguration();
276 
277         OutletConfiguration inheritedOutletConfiguration
278             = inheritedConfiguration.getOutletConfiguration();
279         Map<QualifiedName, Outlet> inheritedOutlets
280             = inheritedOutletConfiguration.getOutlets();
281 
282         for (Map.Entry<QualifiedName, Outlet> entry
283                 : inheritedOutlets.entrySet())
284         {
285             if (!outletConfiguration.outletExists(entry.getKey()))
286             {
287                 outletConfiguration.addOutlet(entry.getValue());
288             }
289         }
290         outletConfiguration.resolveMergepointMappings();
291     }
292 
293     /**
294      * Reads the control configuration and stores it in the unitConfiguration.
295      *
296      * @param unitConfiguration the configuration into which the control
297      *        configuration should be read.
298      * @param unitDescriptor The unit descriptor for the generation unit to
299      *        use.
300      * @param configurationHandlers the available configuration handlers,
301      *        not null.
302      * @param configurationProvider The provider for accessing the
303      *        configuration files.
304      *
305      * @throws ConfigurationException if an error occurs while reading
306      *         the configuration.
307      */
308     private void readControlConfiguration(
309                 UnitConfiguration unitConfiguration,
310                 UnitDescriptor unitDescriptor,
311                 ConfigurationHandlers configurationHandlers,
312                 ConfigurationProvider configurationProvider)
313             throws ConfigurationException
314     {
315         if (log.isDebugEnabled())
316         {
317             log.debug("Start reading control configuration");
318         }
319         ControlConfiguration controlConfiguration
320                 = new ControlConfigurationXmlParser()
321                         .readControllerConfiguration(
322                                 configurationProvider,
323                                 unitDescriptor.getProjectPaths(),
324                                 configurationHandlers);
325         if (unitDescriptor.getLoglevel() == null)
326         {
327             unitConfiguration.setLoglevel(controlConfiguration.getLoglevel());
328             controlConfiguration.getLoglevel().apply();
329         }
330         unitConfiguration.setOutputList(
331                 controlConfiguration.getOutputFiles());
332 
333         {
334             if (log.isDebugEnabled())
335             {
336                 log.debug("Start reading options");
337             }
338             List<OptionsConfiguration> optionConfigurations
339                     = new ArrayList<OptionsConfiguration>();
340             optionConfigurations.addAll(
341                     controlConfiguration.getOptionsConfigurations());
342             if (unitDescriptor.getOverrideOptions() != null)
343             {
344                 optionConfigurations.add(unitDescriptor.getOverrideOptions());
345             }
346 
347             Options options = new Options();
348             for (OptionsConfiguration optionConfiguration
349                     : optionConfigurations)
350             {
351                 options.addGlobalOptions(
352                         optionConfiguration.getOptions(
353                                 configurationProvider));
354             }
355             unitConfiguration.setOptions(options);
356             {
357                 log.debug("End reading options");
358             }
359         }
360         unitConfiguration.setEntityReferences(
361                 controlConfiguration.getEntityReferences());
362         unitConfiguration.setDefaultOutputEncoding(
363                 unitDescriptor.getDefaultOutputEncoding());
364         if (log.isDebugEnabled())
365         {
366             log.debug("Control configuration successfully read.");
367         }
368     }
369 
370     /**
371      * Creates the matching configuration provider for the packaging type
372      * of the unit descriptor.
373      *
374      * @param unitDescriptor the unit descriptor to create the
375      *        configuration provider for, not null.
376      *
377      * @return a configuration provider for the unit descriptor, not null.
378      *
379      * @throws ConfigurationException if an unknown packaging is encountered
380      *         or if a jar file cannot be accessed.
381      */
382     private ConfigurationProvider createConfigurationProvider(
383                 UnitDescriptor unitDescriptor)
384             throws ConfigurationException
385     {
386         ConfigurationProvider configurationProvider;
387         if (UnitDescriptor.Packaging.DIRECTORY == unitDescriptor.getPackaging())
388         {
389             configurationProvider = new DirectoryConfigurationProvider(
390                     unitDescriptor.getProjectPaths(),
391                     unitDescriptor.getConfigurationPaths());
392         }
393         else if (UnitDescriptor.Packaging.JAR == unitDescriptor.getPackaging())
394         {
395             configurationProvider = new JarConfigurationProvider(
396                     unitDescriptor.getProjectPaths(),
397                     unitDescriptor.getConfigurationPaths());
398         }
399         else if (UnitDescriptor.Packaging.CLASSPATH
400                 == unitDescriptor.getPackaging())
401         {
402             configurationProvider = new ClasspathConfigurationProvider(
403                     unitDescriptor.getProjectPaths(),
404                     unitDescriptor.getConfigurationPaths());
405         }
406         else
407         {
408             throw new ConfigurationException("Unknown Unit type "
409                     + unitDescriptor.getPackaging());
410         }
411         return configurationProvider;
412     }
413 
414     private String getUnitDisplayName(UnitDescriptor unitDescriptor)
415     {
416         if (Packaging.CLASSPATH == unitDescriptor.getPackaging())
417         {
418             return unitDescriptor.getProjectPaths().getConfigurationPackage();
419         }
420         else
421         {
422             return unitDescriptor.getProjectPaths().getConfigurationPath()
423                     .toString();
424         }
425     }
426 }