View Javadoc

1   package org.apache.maven.plugin.coreit;
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.io.File;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.OutputStream;
26  import java.lang.reflect.Array;
27  import java.lang.reflect.Method;
28  import java.lang.reflect.Modifier;
29  import java.util.Collection;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.Map;
34  import java.util.Properties;
35  
36  /**
37   * Assists in serializing primitives and beans into properties for later inspection/verification.
38   * 
39   * @author Benjamin Bentmann
40   * @version $Id: PropertyUtil.java 785726 2009-06-17 17:03:34Z bentmann $
41   */
42  class PropertyUtil
43  {
44  
45      private static final Object[] NO_ARGS = {};
46  
47      private static final Class[] NO_PARAMS = {};
48  
49      /**
50       * Serializes the specified object into the given properties, using the provided key. The object may be a scalar
51       * value like a string or some array/collection/map or a bean.
52       * 
53       * @param props The properties to serialize into, must not be <code>null</code>.
54       * @param key The key to use for serialization of the object data, must not be <code>null</code>.
55       * @param obj The object to serialize, may be <code>null</code>.
56       */
57      public static void store( Properties props, String key, Object obj )
58      {
59          store( props, key, obj, new HashSet() );
60      }
61  
62      /**
63       * Serializes the specified object into the given properties, using the provided key. The object may be a scalar
64       * value like a string or some array/collection/map or a bean.
65       * 
66       * @param props The properties to serialize into, must not be <code>null</code>.
67       * @param key The key to use for serialization of the object data, must not be <code>null</code>.
68       * @param obj The object to serialize, may be <code>null</code>.
69       * @param visited The set/stack of already visited objects, used to detect back references in the object graph, must
70       *            not be <code>null</code>.
71       */
72      private static void store( Properties props, String key, Object obj, Collection visited )
73      {
74          if ( obj != null && !visited.contains( obj ) )
75          {
76              visited.add( obj );
77              if ( ( obj instanceof String ) || ( obj instanceof Number ) || ( obj instanceof Boolean )
78                  || ( obj instanceof File ) )
79              {
80                  props.put( key, obj.toString() );
81              }
82              else if ( obj instanceof Collection )
83              {
84                  Collection coll = (Collection) obj;
85                  props.put( key, Integer.toString( coll.size() ) );
86                  int index = 0;
87                  for ( Iterator it = coll.iterator(); it.hasNext(); index++ )
88                  {
89                      Object elem = it.next();
90                      store( props, key + "." + index, elem, visited );
91                  }
92              }
93              else if ( obj instanceof Map )
94              {
95                  Map map = (Map) obj;
96                  props.put( key, Integer.toString( map.size() ) );
97                  int index = 0;
98                  for ( Iterator it = map.entrySet().iterator(); it.hasNext(); index++ )
99                  {
100                     Map.Entry entry = (Map.Entry) it.next();
101                     store( props, key + "." + entry.getKey(), entry.getValue(), visited );
102                 }
103             }
104             else if ( obj.getClass().isArray() )
105             {
106                 int length = Array.getLength( obj );
107                 props.put( key, Integer.toString( length ) );
108                 for ( int index = 0; index < length; index++ )
109                 {
110                     Object elem = Array.get( obj, index );
111                     store( props, key + "." + index, elem, visited );
112                 }
113             }
114             else if ( obj.getClass().getName().endsWith( "Xpp3Dom" ) )
115             {
116                 Class type = obj.getClass();
117                 try
118                 {
119                     Method getValue = type.getMethod( "getValue", NO_PARAMS );
120                     String value = (String) getValue.invoke( obj, NO_ARGS );
121 
122                     if ( value != null )
123                     {
124                         props.put( key + ".value", value );
125                     }
126 
127                     Method getName = type.getMethod( "getName", NO_PARAMS );
128 
129                     Method getChildren = type.getMethod( "getChildren", NO_PARAMS );
130                     Object[] children = (Object[]) getChildren.invoke( obj, NO_ARGS );
131 
132                     props.put( key + ".children", Integer.toString( children.length ) );
133 
134                     Map indices = new HashMap();
135                     for ( int i = 0; i < children.length; i++ )
136                     {
137                         Object child = children[i];
138 
139                         String name = (String) getName.invoke( child, NO_ARGS );
140 
141                         Integer index = (Integer) indices.get( name );
142                         if ( index == null )
143                         {
144                             index = new Integer( 0 );
145                         }
146 
147                         store( props, key + ".children." + name + "." + index, child, visited );
148 
149                         indices.put( name, new Integer( index.intValue() + 1 ) );
150                     }
151                 }
152                 catch ( Exception e )
153                 {
154                     // can't happen
155                 }
156             }
157             else
158             {
159                 Class type = obj.getClass();
160                 Method[] methods = type.getMethods();
161                 for ( int i = 0; i < methods.length; i++ )
162                 {
163                     Method method = methods[i];
164                     if ( Modifier.isStatic( method.getModifiers() ) || method.getParameterTypes().length > 0
165                         || !method.getName().matches( "(get|is)\\p{Lu}.*" ) || method.getName().endsWith( "AsMap" )
166                         || Class.class.isAssignableFrom( method.getReturnType() )
167                         || Object.class.equals( method.getReturnType() ) )
168                     {
169                         continue;
170                     }
171 
172                     try
173                     {
174                         Object value = method.invoke( obj, NO_ARGS );
175                         store( props, key + "." + getPropertyName( method.getName() ), value, visited );
176                     }
177                     catch ( Exception e )
178                     {
179                         // just ignore
180                     }
181                 }
182             }
183             visited.remove( obj );
184         }
185     }
186 
187     /**
188      * Derives the bean property name from the specified method for its getter.
189      * 
190      * @param methodName The method name of the property's getter, must not be <code>null</code>.
191      * @return The property name, never <code>null</code>.
192      */
193     static String getPropertyName( String methodName )
194     {
195         String propertyName = methodName;
196         if ( methodName.startsWith( "get" ) && methodName.length() > 3 )
197         {
198             propertyName = Character.toLowerCase( methodName.charAt( 3 ) ) + methodName.substring( 4 );
199         }
200         else if ( methodName.startsWith( "is" ) && methodName.length() > 2 )
201         {
202             propertyName = Character.toLowerCase( methodName.charAt( 2 ) ) + methodName.substring( 3 );
203         }
204         return propertyName;
205     }
206 
207     /**
208      * Writes the specified properties to the given file.
209      * 
210      * @param props The properties to write, must not be <code>null</code>.
211      * @param file The output file for the properties, must not be <code>null</code>.
212      * @throws IOException If the properties could not be written to the file.
213      */
214     public static void write( Properties props, File file )
215         throws IOException
216     {
217         OutputStream out = null;
218         try
219         {
220             file.getParentFile().mkdirs();
221             out = new FileOutputStream( file );
222             props.store( out, "MAVEN-CORE-IT-LOG" );
223         }
224         finally
225         {
226             if ( out != null )
227             {
228                 try
229                 {
230                     out.close();
231                 }
232                 catch ( IOException e )
233                 {
234                     // just ignore
235                 }
236             }
237         }
238     }
239 
240 }