View Javadoc
1   package org.codehaus.plexus.component.configurator.converters.composite;
2   
3   /*
4    * The MIT License
5    *
6    * Copyright (c) 2004, The Codehaus
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of
9    * this software and associated documentation files (the "Software"), to deal in
10   * the Software without restriction, including without limitation the rights to
11   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12   * of the Software, and to permit persons to whom the Software is furnished to do
13   * so, subject to the following conditions:
14   *
15   * The above copyright notice and this permission notice shall be included in all
16   * copies or substantial portions of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24   * SOFTWARE.
25   */
26  
27  import java.lang.reflect.Modifier;
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.HashSet;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Set;
34  import java.util.SortedSet;
35  import java.util.TreeSet;
36  
37  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
38  import org.codehaus.plexus.component.configurator.ConfigurationListener;
39  import org.codehaus.plexus.component.configurator.converters.AbstractConfigurationConverter;
40  import org.codehaus.plexus.component.configurator.converters.ConfigurationConverter;
41  import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
42  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
43  import org.codehaus.plexus.configuration.PlexusConfiguration;
44  import org.codehaus.plexus.util.StringUtils;
45  
46  /**
47   * @author <a href="mailto:michal@codehaus.org">Michal Maczka</a>
48   */
49  public class CollectionConverter extends AbstractConfigurationConverter {
50      public boolean canConvert(Class type) {
51          return Collection.class.isAssignableFrom(type) && !Map.class.isAssignableFrom(type);
52      }
53  
54      public Object fromConfiguration(
55              ConverterLookup converterLookup,
56              PlexusConfiguration configuration,
57              Class type,
58              Class baseType,
59              ClassLoader classLoader,
60              ExpressionEvaluator expressionEvaluator,
61              ConfigurationListener listener)
62              throws ComponentConfigurationException {
63          Object retValue = fromExpression(configuration, expressionEvaluator, type);
64          if (retValue != null) {
65              return retValue;
66          }
67  
68          Class implementation = getClassForImplementationHint(null, configuration, classLoader);
69  
70          if (implementation != null) {
71              retValue = instantiateObject(implementation);
72          } else {
73              // we can have 2 cases here:
74              //  - provided collection class which is not abstract
75              //     like Vector, ArrayList, HashSet - so we will just instantantiate it
76              // - we have an abtract class so we have to use default collection type
77              int modifiers = type.getModifiers();
78  
79              if (Modifier.isAbstract(modifiers)) {
80                  retValue = getDefaultCollection(type);
81              } else {
82                  try {
83                      retValue = type.newInstance();
84                  } catch (IllegalAccessException e) {
85                      String msg = "An attempt to convert configuration entry " + configuration.getName() + "' into "
86                              + type + " object failed: " + e.getMessage();
87  
88                      throw new ComponentConfigurationException(msg, e);
89                  } catch (InstantiationException e) {
90                      String msg = "An attempt to convert configuration entry " + configuration.getName() + "' into "
91                              + type + " object failed: " + e.getMessage();
92  
93                      throw new ComponentConfigurationException(msg, e);
94                  }
95              }
96          }
97          // now we have collection and we have to add some objects to it
98  
99          for (int i = 0; i < configuration.getChildCount(); i++) {
100             PlexusConfiguration c = configuration.getChild(i);
101             // Object o = null;
102 
103             String configEntry = c.getName();
104 
105             String name = fromXML(configEntry);
106 
107             Class childType = getClassForImplementationHint(null, c, classLoader);
108 
109             if (childType == null && name.indexOf('.') > 0) {
110                 try {
111                     childType = classLoader.loadClass(name);
112                 } catch (ClassNotFoundException e) {
113                     // not found, continue processing
114                 }
115             }
116 
117             if (childType == null) {
118                 // Some classloaders don't create Package objects for classes
119                 // so we have to resort to slicing up the class name
120 
121                 String baseTypeName = baseType.getName();
122 
123                 int lastDot = baseTypeName.lastIndexOf('.');
124 
125                 String className;
126 
127                 if (lastDot == -1) {
128                     className = name;
129                 } else {
130                     String basePackage = baseTypeName.substring(0, lastDot);
131 
132                     className = basePackage + "." + StringUtils.capitalizeFirstLetter(name);
133                 }
134 
135                 try {
136                     childType = classLoader.loadClass(className);
137                 } catch (ClassNotFoundException e) {
138                     if (c.getChildCount() == 0) {
139                         // If no children, try a String.
140                         // TODO: If we had generics we could try that instead - or could the component descriptor list
141                         // an impl?
142                         childType = String.class;
143                     } else {
144                         throw new ComponentConfigurationException("Error loading class '" + className + "'", e);
145                     }
146                 }
147             }
148 
149             ConfigurationConverter converter = converterLookup.lookupConverterForType(childType);
150 
151             Object object = converter.fromConfiguration(
152                     converterLookup, c, childType, baseType, classLoader, expressionEvaluator, listener);
153 
154             Collection collection = (Collection) retValue;
155             collection.add(object);
156         }
157 
158         return retValue;
159     }
160 
161     protected Collection getDefaultCollection(Class collectionType) {
162         Collection retValue = null;
163 
164         if (List.class.isAssignableFrom(collectionType)) {
165             retValue = new ArrayList();
166         } else if (SortedSet.class.isAssignableFrom(collectionType)) {
167             retValue = new TreeSet();
168         } else if (Set.class.isAssignableFrom(collectionType)) {
169             retValue = new HashSet();
170         }
171 
172         return retValue;
173     }
174 }