View Javadoc

1   package com.jayway.maven.plugins.android.config;
2   
3   import java.lang.annotation.Annotation;
4   import java.lang.reflect.Field;
5   import java.lang.reflect.Method;
6   import java.util.ArrayList;
7   import java.util.Collection;
8   
9   /**
10   * ConfigHandler is able to parse the configuration of a Mojo based on the Maven injected parameters as well as a config
11   * pojo and annontations for default values on properties named parsed*. See the ProguardMojo for a working
12   * implementation.
13   * 
14   * @author Adrian Stabiszewski https://github.com/grundid/
15   * @author Manfred Moser <manfred@simpligility.com>
16   * @see ConfigPojo
17   * @see PullParameter
18   */
19  public class ConfigHandler
20  {
21  
22      private Object mojo;
23      private Object configPojoInstance;
24      private String configPojoName;
25      private String configPojoPrefix;
26  
27      public ConfigHandler( Object mojo )
28      {
29          this.mojo = mojo;
30          initConfigPojo();
31      }
32  
33      private Collection< Field > findPropertiesByAnnotation( Class< ? extends Annotation > annotation )
34      {
35          Collection< Field > result = new ArrayList< Field >();
36          for ( Field field : mojo.getClass().getDeclaredFields() )
37          {
38              if ( field.isAnnotationPresent( annotation ) )
39              {
40                  field.setAccessible( true );
41                  result.add( field );
42              }
43          }
44          return result;
45      }
46  
47      public void parseConfiguration()
48      {
49          Collection< Field > parsedFields = findPropertiesByAnnotation( PullParameter.class );
50  
51          for ( Field field : parsedFields )
52          {
53              Object value = null;
54              String fieldBaseName = getFieldNameWithoutParsedPrefix( field );
55              // first take the setting from the config pojo (e.g. nested config in plugin configuration)
56              if ( configPojoInstance != null )
57              {
58                  value = getValueFromPojo( fieldBaseName );
59              }
60              // then override with value from properties supplied in pom, settings or command line
61              // unless it is null or an empty array
62              Object propertyValue = getValueFromMojo( fieldBaseName );
63              if ( propertyValue == null || propertyValue instanceof Object[]//
64                      && ( (Object[]) propertyValue ).length == 0 )
65              {
66                  // no useful value
67              }
68              else
69              {
70                  value = propertyValue;
71              }
72              // and only if we still have no value, get the default as declared in the annotation
73              if ( value == null )
74              {
75                  value = getValueFromAnnotation( field );
76              }
77  
78              try
79              {
80                  field.set( mojo, value );
81              }
82              catch ( Exception e )
83              {
84                  e.printStackTrace();
85              }
86          }
87      }
88  
89      private Object getValueFromAnnotation( Field field )
90      {
91          PullParameter annotation = field.getAnnotation( PullParameter.class );
92          String defaultValue = annotation.defaultValue();
93          boolean required = annotation.required();
94          String currentParameterName = "android." + configPojoName + "." + getFieldNameWithoutParsedPrefix( field );
95  
96          if ( !defaultValue.isEmpty() )
97          { // TODO find a better way to define an empty default value
98              Class< ? > fieldType = field.getType();
99              if ( fieldType.isAssignableFrom( String.class ) )
100             {
101                 return defaultValue;
102             }
103             else
104             {
105                 if ( fieldType.isAssignableFrom( Boolean.class ) )
106                 {
107                     return Boolean.valueOf( defaultValue );
108                 }
109                 if ( fieldType.isAssignableFrom( Long.class ) )
110                 {
111                     return Long.valueOf( defaultValue );
112                 }
113                 if ( fieldType.isAssignableFrom( Integer.class ) )
114                 {
115                     return Integer.valueOf( defaultValue );
116                 }
117             }
118 
119             // TODO add more handler types as required, for example integer, long, ... we will do that when we encounter
120             // them in other mojos..
121             throw new RuntimeException( "No handler for type " + fieldType + " on " //
122                     + currentParameterName + " found." );
123         }
124         else
125         {
126             if ( !required )
127             {
128                 try
129                 {
130                     Method method = mojo.getClass().getDeclaredMethod( annotation.defaultValueGetterMethod() );
131                     // even access it if the method is private
132                     method.setAccessible( true );
133                     return method.invoke( mojo );
134                 }
135                 catch ( Exception e )
136                 {
137                     throw new RuntimeException( "Problem encountered accessing default value for "
138                             + currentParameterName + " parameter", e );
139                 }
140             }
141             else
142             {
143                 throw new RuntimeException( "Required parameter " + currentParameterName + " has no value. Please "
144                         + "supply with -D" + currentParameterName + "=value on the command line or as property or "
145                         + "plugin configuration in your pom or settings file." );
146             }
147         }
148     }
149 
150     private Object getValueFromMojo( String fieldBaseName )
151     {
152         return getValueFromObject( mojo, configPojoName + toFirstLetterUppercase( fieldBaseName ) );
153     }
154 
155     private Object getValueFromPojo( String fieldBaseName )
156     {
157         return getValueFromObject( configPojoInstance, fieldBaseName );
158     }
159 
160     private Object getValueFromObject( Object object, String fieldBaseName )
161     {
162         Object value = null;
163         try
164         {
165             Field pojoField = findFieldByName( object, fieldBaseName );
166             if ( pojoField != null )
167             {
168                 value = pojoField.get( object );
169             }
170         }
171         catch ( Exception e )
172         {
173             // swallow
174         }
175         return value;
176     }
177 
178     private Field findFieldByName( Object object, String name )
179     {
180         for ( Field field : object.getClass().getDeclaredFields() )
181         {
182             if ( field.getName().equals( name ) )
183             {
184                 field.setAccessible( true );
185                 return field;
186             }
187         }
188         return null;
189     }
190 
191     private String getFieldNameWithoutPrefix( Field field, String prefix )
192     {
193         if ( field.getName().startsWith( prefix ) )
194         {
195             String fieldName = field.getName().substring( prefix.length() );
196             return fieldName.substring( 0, 1 ).toLowerCase() + fieldName.substring( 1 );
197         }
198         else
199         {
200             return field.getName();
201         }
202     }
203 
204     private String toFirstLetterUppercase( String s )
205     {
206         return s.substring( 0, 1 ).toUpperCase() + s.substring( 1 );
207     }
208 
209     private String getFieldNameWithoutParsedPrefix( Field field )
210     {
211         return getFieldNameWithoutPrefix( field, configPojoPrefix );
212     }
213 
214     private void initConfigPojo()
215     {
216         try
217         {
218             Field configPojo = findPropertiesByAnnotation( ConfigPojo.class ).iterator().next();
219             configPojoName = configPojo.getName();
220             configPojoInstance = configPojo.get( mojo );
221             configPojoPrefix = configPojo.getAnnotation( ConfigPojo.class ).prefix();
222         }
223         catch ( Exception e )
224         {
225             // ignore, we can live without a config pojo
226         }
227     }
228 }