View Javadoc

1   /*
2    * Copyright 2006-2007-2007 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package net.sf.ezmorph.bean;
18  
19  import java.io.Serializable;
20  import java.util.Arrays;
21  import java.util.Comparator;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.Map;
25  
26  import net.sf.ezmorph.MorphException;
27  import net.sf.ezmorph.MorphUtils;
28  import net.sf.ezmorph.MorpherRegistry;
29  
30  import org.apache.commons.beanutils.DynaBean;
31  import org.apache.commons.beanutils.DynaClass;
32  import org.apache.commons.beanutils.DynaProperty;
33  import org.apache.commons.lang.builder.EqualsBuilder;
34  import org.apache.commons.lang.builder.HashCodeBuilder;
35  import org.apache.commons.lang.builder.ToStringBuilder;
36  
37  /**
38   * @author Andres Almiray <aalmiray@users.sourceforge.net>
39   */
40  public final class MorphDynaClass implements DynaClass, Serializable
41  {
42     private static final Comparator dynaPropertyComparator = new Comparator(){
43        public int compare( Object a, Object b )
44        {
45           if( a instanceof DynaProperty && b instanceof DynaProperty ){
46              DynaProperty p1 = (DynaProperty) a;
47              DynaProperty p2 = (DynaProperty) b;
48              return p1.getName()
49                    .compareTo( p2.getName() );
50           }
51           return -1;
52        }
53     };
54  
55     private static final long serialVersionUID = -613214016860871560L;
56  
57     private Map attributes;
58     private Class beanClass;
59     private DynaProperty dynaProperties[];
60     private String name;
61     private Map properties = new HashMap();
62     private Class type;
63  
64     public MorphDynaClass( Map attributes )
65     {
66        this( null, null, attributes );
67     }
68  
69     public MorphDynaClass( Map attributes, boolean exceptionOnEmptyAttributes )
70     {
71        this( null, null, attributes, exceptionOnEmptyAttributes );
72     }
73  
74     public MorphDynaClass( String name, Class type, Map attributes )
75     {
76        this( name, type, attributes, false );
77     }
78  
79     public MorphDynaClass( String name, Class type, Map attributes,
80           boolean exceptionOnEmptyAttributes )
81     {
82        if( name == null ){
83           name = "MorphDynaClass";
84        }
85        if( type == null ){
86           type = MorphDynaBean.class;
87        }
88        if( !MorphDynaBean.class.isAssignableFrom( type ) ){
89           throw new MorphException( "MorphDynaBean is not assignable from " + type.getName() );
90        }
91        if( attributes == null || attributes.isEmpty() ){
92           if( exceptionOnEmptyAttributes ){
93              throw new MorphException( "Attributes map is null or empty." );
94           }else{
95              attributes = new HashMap();
96           }
97        }
98        this.name = name;
99        this.type = type;
100       this.attributes = attributes;
101       process();
102    }
103 
104    public boolean equals( Object obj )
105    {
106       if( this == obj ){
107          return true;
108       }
109 
110       if( obj == null ){
111          return false;
112       }
113 
114       if( !(obj instanceof MorphDynaClass) ){
115          return false;
116       }
117 
118       MorphDynaClass other = (MorphDynaClass) obj;
119       EqualsBuilder builder = new EqualsBuilder().append( this.name, other.name )
120             .append( this.type, other.type );
121       if( dynaProperties.length != other.dynaProperties.length ){
122          return false;
123       }
124       for( int i = 0; i < dynaProperties.length; i++ ){
125          DynaProperty a = this.dynaProperties[i];
126          DynaProperty b = other.dynaProperties[i];
127          builder.append( a.getName(), b.getName() );
128          builder.append( a.getType(), b.getType() );
129       }
130       return builder.isEquals();
131    }
132 
133    public DynaProperty[] getDynaProperties()
134    {
135       return dynaProperties;
136    }
137 
138    public DynaProperty getDynaProperty( String propertyName )
139    {
140       if( propertyName == null ){
141          throw new MorphException( "Unnespecified bean property name" );
142 
143       }
144       return (DynaProperty) properties.get( propertyName );
145    }
146 
147    public String getName()
148    {
149       return this.name;
150    }
151 
152    public int hashCode()
153    {
154       HashCodeBuilder builder = new HashCodeBuilder().append( name )
155             .append( type );
156       for( int i = 0; i < dynaProperties.length; i++ ){
157          builder.append( this.dynaProperties[i].getName() );
158          builder.append( this.dynaProperties[i].getType() );
159       }
160       return builder.toHashCode();
161    }
162 
163    public DynaBean newInstance() throws IllegalAccessException, InstantiationException
164    {
165       return newInstance( null );
166    }
167 
168    public DynaBean newInstance( MorpherRegistry morpherRegistry ) throws IllegalAccessException,
169          InstantiationException
170    {
171       if( morpherRegistry == null ){
172          morpherRegistry = new MorpherRegistry();
173          MorphUtils.registerStandardMorphers( morpherRegistry );
174       }
175       MorphDynaBean dynaBean = (MorphDynaBean) getBeanClass().newInstance();
176       dynaBean.setDynaBeanClass( this );
177       dynaBean.setMorpherRegistry( morpherRegistry );
178       Iterator keys = attributes.keySet()
179             .iterator();
180       while( keys.hasNext() ){
181          String key = (String) keys.next();
182          dynaBean.set( key, null );
183       }
184       return dynaBean;
185    }
186 
187    public String toString()
188    {
189       return new ToStringBuilder( this ).append( "name", this.name )
190             .append( "type", this.type )
191             .append( "attributes", this.attributes )
192             .toString();
193    }
194 
195    protected Class getBeanClass()
196    {
197       if( this.beanClass == null ){
198          process();
199       }
200       return this.beanClass;
201    }
202 
203    private void process()
204    {
205       this.beanClass = this.type;
206 
207       try{
208          Iterator entries = attributes.entrySet()
209                .iterator();
210          dynaProperties = new DynaProperty[attributes.size()];
211          int i = 0;
212          while( entries.hasNext() ){
213             Map.Entry entry = (Map.Entry) entries.next();
214             String pname = (String) entry.getKey();
215             Object pclass = entry.getValue();
216             DynaProperty dynaProperty = null;
217             if( pclass instanceof String ){
218                Class klass = (Class) Class.forName( (String) pclass );
219                if( klass.isArray() && klass.getComponentType()
220                      .isArray() ){
221                   throw new MorphException( "Multidimensional arrays are not supported" );
222                }
223                dynaProperty = new DynaProperty( pname, klass );
224             }else if( pclass instanceof Class ){
225                Class klass = (Class) pclass;
226                if( klass.isArray() && klass.getComponentType()
227                      .isArray() ){
228                   throw new MorphException( "Multidimensional arrays are not supported" );
229                }
230                dynaProperty = new DynaProperty( pname, klass );
231             }else{
232                throw new MorphException( "Type must be String or Class" );
233             }
234             properties.put( dynaProperty.getName(), dynaProperty );
235             dynaProperties[i++] = dynaProperty;
236          }
237       }
238       catch( ClassNotFoundException cnfe ){
239          throw new MorphException( cnfe );
240       }
241 
242       // keep properties sorted by name
243       Arrays.sort( dynaProperties, 0, dynaProperties.length, dynaPropertyComparator );
244    }
245 }