View Javadoc
1   package org.codehaus.plexus.component.configurator.converters;
2   
3   /*
4    * Copyright 2005-2007 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
20  import org.codehaus.plexus.component.configurator.ConfigurationListener;
21  import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
22  import org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup;
23  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
24  import org.codehaus.plexus.configuration.PlexusConfiguration;
25  import org.codehaus.plexus.util.ReflectionUtils;
26  
27  import java.lang.reflect.Field;
28  import java.lang.reflect.InvocationTargetException;
29  import java.lang.reflect.Method;
30  
31  
32  /** @author <a href="mailto:kenney@codehaus.org">Kenney Westerhof</a> */
33  public class ComponentValueSetter
34  {
35      private Object object;
36  
37      private String fieldName;
38  
39      private ConverterLookup lookup;
40  
41      private Method setter;
42  
43      private Class setterParamType;
44  
45      private ConfigurationConverter setterTypeConverter;
46  
47      private Field field;
48  
49      private Class fieldType;
50  
51      private ConfigurationConverter fieldTypeConverter;
52  
53      private ConfigurationListener listener;
54  
55      public ComponentValueSetter( String fieldName,
56                                   Object object,
57                                   ConverterLookup lookup )
58          throws ComponentConfigurationException
59      {
60          this( fieldName, object, lookup, null );
61      }
62  
63      public ComponentValueSetter( String fieldName,
64                                   Object object,
65                                   ConverterLookup lookup,
66                                   ConfigurationListener listener )
67          throws ComponentConfigurationException
68      {
69          this.fieldName = fieldName;
70          this.object = object;
71          this.lookup = lookup;
72          this.listener = listener;
73  
74          if ( object == null )
75          {
76              throw new ComponentConfigurationException( "Component is null" );
77          }
78  
79          initSetter();
80  
81          initField();
82  
83          if ( setter == null && field == null )
84          {
85              throw new ComponentConfigurationException(
86                  "Cannot find setter nor field in " + object.getClass().getName() + " for '" + fieldName + "'" );
87          }
88  
89          if ( setterTypeConverter == null && fieldTypeConverter == null )
90          {
91              throw new ComponentConfigurationException(
92                  "Cannot find converter for " + setterParamType.getName() + ( fieldType != null && !fieldType.equals(
93                      setterParamType ) ? " or " + fieldType.getName() : "" ) );
94          }
95      }
96  
97      private void initSetter()
98      {
99          setter = ReflectionUtils.getSetter( fieldName, object.getClass() );
100 
101         if ( setter == null )
102         {
103             return;
104         }
105 
106         setterParamType = setter.getParameterTypes()[0];
107 
108         try
109         {
110             setterTypeConverter = lookup.lookupConverterForType( setterParamType );
111         }
112         catch ( ComponentConfigurationException e )
113         {
114             // ignore, handle later
115         }
116     }
117 
118     private void initField()
119     {
120         field = ReflectionUtils.getFieldByNameIncludingSuperclasses( fieldName, object.getClass() );
121 
122         if ( field == null )
123         {
124             return;
125         }
126 
127         fieldType = field.getType();
128 
129         try
130         {
131             fieldTypeConverter = lookup.lookupConverterForType( fieldType );
132         }
133         catch ( ComponentConfigurationException e )
134         {
135             // ignore, handle later
136         }
137     }
138 
139     private void setValueUsingField( Object value )
140         throws ComponentConfigurationException
141     {
142         try
143         {
144             boolean wasAccessible = field.isAccessible();
145 
146             if ( !wasAccessible )
147             {
148                 field.setAccessible( true );
149             }
150 
151             if ( listener != null )
152             {
153                 listener.notifyFieldChangeUsingReflection( fieldName, value, object );
154             }
155 
156             field.set( object, value );
157 
158             if ( !wasAccessible )
159             {
160                 field.setAccessible( false );
161             }
162         }
163         catch ( IllegalAccessException e )
164         {
165             throw new ComponentConfigurationException( "Cannot access field: " + field, e );
166         }
167         catch ( IllegalArgumentException e )
168         {
169             throw new ComponentConfigurationException( "Cannot assign value '" + value + "' (type: "
170                 + value.getClass() + ") to " + field, e );
171         }
172     }
173 
174     private void setValueUsingSetter( Object value )
175         throws ComponentConfigurationException
176     {
177         if ( setterParamType == null || setter == null )
178         {
179             throw new ComponentConfigurationException( "No setter found" );
180         }
181 
182         String exceptionInfo = object.getClass().getName() + "." + setter.getName() + "( " + setterParamType.getClass().getName() + " )";
183 
184         if ( listener != null )
185         {
186             listener.notifyFieldChangeUsingSetter( fieldName, value, object );
187         }
188 
189         try
190         {
191             setter.invoke( object, new Object[]{value} );
192         }
193         catch ( IllegalAccessException e )
194         {
195             throw new ComponentConfigurationException( "Cannot access method: " + exceptionInfo, e );
196         }
197         catch ( IllegalArgumentException e )
198         {
199             throw new ComponentConfigurationException(
200                 "Invalid parameter supplied while setting '" + value + "' to " + exceptionInfo, e );
201         }
202         catch ( InvocationTargetException e )
203         {
204             throw new ComponentConfigurationException( "Setter " + exceptionInfo +
205                 " threw exception when called with parameter '" + value + "': " + e.getTargetException().getMessage(),
206                 e );
207         }
208     }
209 
210     public void configure( PlexusConfiguration config, ClassLoader classLoader, ExpressionEvaluator evaluator )
211         throws ComponentConfigurationException
212     {
213         Object value = null;
214 
215         // try setter converter + method first
216 
217         if ( setterTypeConverter != null )
218         {
219             try
220             {
221                 value = setterTypeConverter.fromConfiguration( lookup, config, setterParamType, object.getClass(), classLoader, evaluator, listener );
222 
223                 if ( value != null )
224                 {
225                     setValueUsingSetter( value );
226 
227                     return;
228                 }
229             }
230             catch ( ComponentConfigurationException e )
231             {
232                 if ( fieldTypeConverter == null || fieldTypeConverter.getClass().equals( setterTypeConverter.getClass() ) )
233                 {
234                     throw e;
235                 }
236             }
237         }
238 
239         // try setting field using value found with method
240         // converter, if present.
241 
242         ComponentConfigurationException savedEx = null;
243 
244         if ( value != null )
245         {
246             try
247             {
248                 setValueUsingField( value );
249                 return;
250             }
251             catch ( ComponentConfigurationException e )
252             {
253                 savedEx = e;
254             }
255         }
256 
257         // either no value or setting went wrong. Try
258         // new converter.
259 
260         value = fieldTypeConverter.fromConfiguration( lookup, config, fieldType, object.getClass(), classLoader, evaluator, listener );
261 
262         if ( value != null )
263         {
264             setValueUsingField( value );
265         }
266         // FIXME: need this?
267         else if ( savedEx != null )
268         {
269             throw savedEx;
270         }
271     }
272 
273 }