001 package org.rakeshv;
002
003 import java.lang.reflect.Field;
004 import java.lang.reflect.Method;
005 import java.util.Collection;
006 import java.util.Iterator;
007 import java.util.Map;
008 import java.util.logging.Logger;
009
010 /**
011 * A <code>sub-class</code> of <code>java.lang.Object</code> that is
012 * meant to be used as the <code>base-class</code> for all classes.
013 * This class provides an over-ridden {@link #toString()} method that
014 * returns an XML representation of all the <code>fields</code> in a
015 * class that have Java Bean style accessor methods.
016 *
017 * <p>Copyright 2004 Rakesh Vidyadharan</p>
018 * @author Rakesh Vidyadharan 2004 October 3
019 * @version $Id: BaseObject.java,v 1.3 2004/11/06 20:40:55 rakesh Exp $
020 */
021 public class BaseObject extends Object
022 {
023 /**
024 * A logger used to log errors.
025 */
026 private static final Logger logger =
027 Logger.getLogger( "org.rakeshv.BaseObject" );
028
029 /**
030 * The end of line characters to use to delimit lines.
031 */
032 public static final String END_OF_LINE =
033 System.getProperty( "line.separator" );
034
035 /**
036 * Returns a string that presents an XML representation of the
037 * data encapsulated in this object.
038 *
039 * @return String - The XML representation of the object.
040 */
041 public String toString()
042 {
043 StringBuffer buffer = new StringBuffer( 1024 );
044
045 buffer.append( "<" );
046 buffer.append( this.getClass().getName() );
047 buffer.append( ">" );
048 buffer.append( BaseObject.END_OF_LINE );
049
050 try
051 {
052 Field[] fields = this.getClass().getDeclaredFields();
053 for ( int i = 0; i < fields.length; ++i )
054 {
055 printField( fields[i], buffer );
056 }
057 }
058 catch ( Throwable t )
059 {
060 logger.warning( "Error reflecting on object fields or methods. " +
061 t.toString() );
062 }
063
064 buffer.append( "</" );
065 buffer.append( this.getClass().getName() );
066 buffer.append( ">" );
067 buffer.append( BaseObject.END_OF_LINE );
068
069 return buffer.toString();
070 }
071
072 /**
073 * Fetch the value of the specified <code>Field</code> using its
074 * <code>accessor</code> method (if it exists). Write the XML
075 * representation of the data encapsulated in the field to the
076 * specified <code>StringBuffer</code>.
077 *
078 * @param field The field whose XML representation is to be derived.
079 * @param buffer The StringBuffer to which the field's XML
080 * representation is to be written.
081 */
082 private void printField( Field field, StringBuffer buffer )
083 {
084 try
085 {
086 String fieldName = field.getName();
087 String methodName = "get" +
088 fieldName.substring( 0, 1 ).toUpperCase() +
089 fieldName.substring( 1 );
090 Method method = this.getClass().getDeclaredMethod(
091 methodName, new Class[0] );
092
093 buffer.append( "<" );
094 buffer.append( fieldName );
095 buffer.append( " type='" );
096 buffer.append( field.getType().getName() );
097 buffer.append( "'>" );
098
099 Object result = method.invoke( this, null );
100 if ( result == null )
101 {
102 throw new CustomException( "Accessor method for field " +
103 fieldName + " returns void!" );
104 }
105
106 try
107 {
108 Collection collection = (Collection) result;
109 printCollection( collection, buffer );
110 }
111 catch ( ClassCastException cex )
112 {
113 try
114 {
115 Map map = (Map) result;
116 printMap( map, buffer );
117 }
118 catch ( ClassCastException cex1 )
119 {
120 buffer.append( result );
121 }
122 }
123
124 buffer.append( "</" );
125 buffer.append( field.getName() );
126 buffer.append( ">" );
127 buffer.append( BaseObject.END_OF_LINE );
128 }
129 catch ( Throwable t )
130 {
131 logger.warning( "Error fetching data for field " +
132 field.getName() + "." );
133 }
134 }
135
136 /**
137 * Append XML representations of each element stored in the
138 * <code>Collection</code> to the specified <code>StringBuffer</code>.
139 * This method will be invoked recursively for elements that are
140 * themselves collections.
141 *
142 * @see #printMap( Map, StringBuffer )
143 */
144 protected void printCollection( Collection collection,
145 StringBuffer buffer )
146 {
147 buffer.append( BaseObject.END_OF_LINE );
148 buffer.append( "<collection>" );
149 buffer.append( BaseObject.END_OF_LINE );
150
151 for ( Iterator iterator = collection.iterator();
152 iterator.hasNext(); )
153 {
154 Object object = iterator.next();
155
156 buffer.append( "<entry type='" );
157 buffer.append( object.getClass().getName() );
158 buffer.append( "'>" );
159 buffer.append( BaseObject.END_OF_LINE );
160
161 if ( object instanceof java.util.Collection )
162 {
163 printCollection( (Collection) object, buffer );
164 }
165 else if ( object instanceof java.util.Map )
166 {
167 printMap( (Map) object, buffer );
168 }
169 else
170 {
171 buffer.append( object );
172 buffer.append( BaseObject.END_OF_LINE );
173 }
174
175 buffer.append( "</entry>" );
176 buffer.append( BaseObject.END_OF_LINE );
177 }
178
179 buffer.append( "</collection>" );
180 buffer.append( BaseObject.END_OF_LINE );
181 }
182
183 /**
184 * Append an XML representation of the <code>key-value</code>
185 * mappings stored in the specified <code>Map</code> to the specified
186 * <code>StringBuffer</code>. This method invokes itself recursively
187 * for <code>values</code> that are themselves maps.
188 *
189 * @param map The map whose XML representation is to be generated.
190 * @param buffer The StringBuffer to which the XML representation is
191 * to be appended.
192 */
193 protected void printMap( Map map, StringBuffer buffer )
194 {
195 buffer.append( BaseObject.END_OF_LINE );
196 buffer.append( "<map>" );
197 buffer.append( BaseObject.END_OF_LINE );
198
199 for ( Iterator iterator = map.keySet().iterator();
200 iterator.hasNext(); )
201 {
202 Object key = iterator.next();
203 Object value = map.get( key );
204
205 buffer.append( "<entry>" );
206 buffer.append( BaseObject.END_OF_LINE );
207
208 buffer.append( "<key type='" );
209 buffer.append( key.getClass().getName() );
210 buffer.append( "'>" );
211 buffer.append( key );
212 buffer.append( "</key>" );
213 buffer.append( BaseObject.END_OF_LINE );
214
215 buffer.append( "<value type='" );
216 buffer.append( value.getClass().getName() );
217 buffer.append( "'>" );
218 buffer.append( BaseObject.END_OF_LINE );
219
220 if ( value instanceof java.util.Collection )
221 {
222 printCollection( (Collection) value, buffer );
223 }
224 else if ( value instanceof java.util.Map )
225 {
226 printMap( (Map) value, buffer );
227 }
228 else
229 {
230 buffer.append( value );
231 buffer.append( BaseObject.END_OF_LINE );
232 }
233
234 buffer.append( "</value>" );
235 buffer.append( BaseObject.END_OF_LINE );
236
237 buffer.append( "</entry>" );
238 buffer.append( BaseObject.END_OF_LINE );
239 }
240
241 buffer.append( "</map>" );
242 buffer.append( BaseObject.END_OF_LINE );
243 }
244 }