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 org.codehaus.plexus.component.configurator.ComponentConfigurationException;
28  import org.codehaus.plexus.component.configurator.ConfigurationListener;
29  import org.codehaus.plexus.component.configurator.converters.AbstractConfigurationConverter;
30  import org.codehaus.plexus.component.configurator.converters.ConfigurationConverter;
31  import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
32  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
33  import org.codehaus.plexus.configuration.PlexusConfiguration;
34  import org.codehaus.plexus.util.StringUtils;
35  
36  import java.lang.reflect.Modifier;
37  import java.util.ArrayList;
38  import java.util.Collection;
39  import java.util.HashSet;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.Set;
43  import java.util.SortedSet;
44  import java.util.TreeSet;
45  
46  
47  /**
48   * @author <a href="mailto:michal@codehaus.org">Michal Maczka</a>
49   * @version $Id$
50   */
51  public class CollectionConverter
52      extends AbstractConfigurationConverter
53  {
54      public boolean canConvert( Class type )
55      {
56          return Collection.class.isAssignableFrom( type ) && !Map.class.isAssignableFrom( type );
57      }
58  
59      public Object fromConfiguration( ConverterLookup converterLookup, PlexusConfiguration configuration, Class type,
60                                       Class baseType, ClassLoader classLoader, ExpressionEvaluator expressionEvaluator,
61                                       ConfigurationListener listener )
62          throws ComponentConfigurationException
63      {
64          Object retValue = fromExpression( configuration, expressionEvaluator, type );
65          if ( retValue != null )
66          {
67              return retValue;
68          }
69  
70          Class implementation = getClassForImplementationHint( null, configuration, classLoader );
71  
72          if ( implementation != null )
73          {
74              retValue = instantiateObject( implementation );
75          }
76          else
77          {
78              // we can have 2 cases here:
79              //  - provided collection class which is not abstract
80              //     like Vector, ArrayList, HashSet - so we will just instantantiate it
81              // - we have an abtract class so we have to use default collection type
82              int modifiers = type.getModifiers();
83  
84              if ( Modifier.isAbstract( modifiers ) )
85              {
86                  retValue = getDefaultCollection( type );
87              }
88              else
89              {
90                  try
91                  {
92                      retValue = type.newInstance();
93                  }
94                  catch ( IllegalAccessException e )
95                  {
96                      String msg = "An attempt to convert configuration entry " + configuration.getName() + "' into " +
97                          type + " object failed: " + e.getMessage();
98  
99                      throw new ComponentConfigurationException( msg, e );
100                 }
101                 catch ( InstantiationException e )
102                 {
103                     String msg = "An attempt to convert configuration entry " + configuration.getName() + "' into " +
104                         type + " object failed: " + e.getMessage();
105 
106                     throw new ComponentConfigurationException( msg, e );
107                 }
108             }
109         }
110         // now we have collection and we have to add some objects to it
111 
112         for ( int i = 0; i < configuration.getChildCount(); i++ )
113         {
114             PlexusConfiguration c = configuration.getChild( i );
115             //Object o = null;
116 
117             String configEntry = c.getName();
118 
119             String name = fromXML( configEntry );
120 
121             Class childType = getClassForImplementationHint( null, c, classLoader );
122 
123             if ( childType == null && name.indexOf( '.' ) > 0 )
124             {
125                 try
126                 {
127                     childType = classLoader.loadClass( name );
128                 }
129                 catch ( ClassNotFoundException e )
130                 {
131                     // not found, continue processing
132                 }
133             }
134 
135             if ( childType == null )
136             {
137                 // Some classloaders don't create Package objects for classes
138                 // so we have to resort to slicing up the class name
139 
140                 String baseTypeName = baseType.getName();
141 
142                 int lastDot = baseTypeName.lastIndexOf( '.' );
143 
144                 String className;
145 
146                 if ( lastDot == -1 )
147                 {
148                     className = name;
149                 }
150                 else
151                 {
152                     String basePackage = baseTypeName.substring( 0, lastDot );
153 
154                     className = basePackage + "." + StringUtils.capitalizeFirstLetter( name );
155                 }
156 
157                 try
158                 {
159                     childType = classLoader.loadClass( className );
160                 }
161                 catch ( ClassNotFoundException e )
162                 {
163                     if ( c.getChildCount() == 0 )
164                     {
165                         // If no children, try a String.
166                         // TODO: If we had generics we could try that instead - or could the component descriptor list an impl?
167                         childType = String.class;
168                     }
169                     else
170                     {
171                         throw new ComponentConfigurationException( "Error loading class '" + className + "'", e );
172                     }
173                 }
174             }
175 
176             ConfigurationConverter converter = converterLookup.lookupConverterForType( childType );
177 
178             Object object = converter.fromConfiguration( converterLookup, c, childType, baseType, classLoader,
179                                                          expressionEvaluator, listener );
180 
181             Collection collection = (Collection) retValue;
182             collection.add( object );
183         }
184 
185         return retValue;
186     }
187 
188     protected Collection getDefaultCollection( Class collectionType )
189     {
190         Collection retValue = null;
191 
192         if ( List.class.isAssignableFrom( collectionType ) )
193         {
194             retValue = new ArrayList();
195         }
196         else if ( SortedSet.class.isAssignableFrom( collectionType ) )
197         {
198             retValue = new TreeSet();
199         }
200         else if ( Set.class.isAssignableFrom( collectionType ) )
201         {
202             retValue = new HashSet();
203         }
204 
205         return retValue;
206     }
207 
208 }