Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/progeeks/meta/MetaClass.java


1   /*
2    * $Id: MetaClass.java,v 1.11 2003/09/20 11:07:09 pspeed Exp $
3    *
4    * Copyright (c) 2001-2002, Paul Speed
5    * All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1) Redistributions of source code must retain the above copyright notice,
12   *    this list of conditions and the following disclaimer.
13   * 2) Redistributions in binary form must reproduce the above copyright
14   *    notice, this list of conditions and the following disclaimer in the
15   *    documentation and/or other materials provided with the distribution.
16   * 3) Neither the names "Progeeks", "Meta-JB", nor the names of its contributors
17   *    may be used to endorse or promote products derived from this software
18   *    without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   */
32  
33  package org.progeeks.meta;
34  
35  import java.util.*;
36  
37  /**
38   *  Describes the properties associated with a meta-object.
39   *  MetaClass objects must be created through the factory methods
40   *  provided by the MetaClassRegistry to which they will belong.
41   *
42   *  @version   $Revision: 1.11 $
43   *  @author    Paul Speed
44   */
45  public class MetaClass
46  {
47      private MetaClassRegistry classRegistry;
48      private String name;
49      private Map properties = new LinkedHashMap();
50      private List superclasses = new ArrayList();
51      private boolean resolved = false;
52  
53      /**
54       *  Creates the meta-class using the specified parameters.
55       */
56      protected MetaClass( MetaClassRegistry classRegistry, String name, Collection propertyInfo )
57      {
58          this( classRegistry, name, propertyInfo, Collections.EMPTY_LIST );
59      }
60  
61      /**
62       *  Creates the meta-class using the specified parameters.
63       */
64      protected MetaClass( MetaClassRegistry classRegistry, String name, Collection propertyInfo,
65                           Collection superclasses )
66      {
67          if( name == null )
68              throw new RuntimeException( "Name cannot be null." );
69  
70          this.classRegistry = classRegistry;
71          this.name = name;
72  
73          // Possible class hierarchies:
74          //
75          // Simple:
76          // A <- B <- C
77          //
78          // Multiple:
79          // A  <-  C
80          // B  <-
81          //
82          // C should have all of A's properties and any of B's that
83          // aren't defined in A.
84          //
85          // Complex:
86          // A <-\
87          // B <--C-\
88          //          G
89          // B <--F-/
90          // D <-/
91          //
92          // G should have all of C and F's properties, only
93          // one set of B's properties (that aren't in C or F)
94          // and any of A and D's properties (that aren't in C or F).
95          // I think looking at C and F's full property set is probably
96          // enough... just check for dupes and conflicts at that level.
97  
98          for( Iterator i = superclasses.iterator(); i.hasNext(); )
99              {
100             MetaClass mc = (MetaClass)i.next();
101             if( this.superclasses.contains( mc ) )
102                 continue;
103             this.superclasses.add( mc );
104 
105             // Go ahead and add the properties from the meta-class
106             for( Iterator j = mc.getPropertyInfos().iterator(); j.hasNext(); )
107                 {
108                 PropertyInfo info = (PropertyInfo)j.next();
109                 addProperty( info );
110                 }
111             }
112 
113         for( Iterator i = propertyInfo.iterator(); i.hasNext(); )
114             {
115             PropertyInfo info = (PropertyInfo)i.next();
116             addProperty( info );
117             }
118     }
119 
120     /**
121      *  Creates the meta-class using the specified parameters.
122      */
123     protected MetaClass( MetaClassRegistry classRegistry, String name, Collection propertyInfo,
124                          MetaClass superclass )
125     {
126         this( classRegistry, name, propertyInfo, Arrays.asList( new MetaClass[] { superclass } ) );
127     }
128 
129     /**
130      *  Called internally to resolve a property type if
131      *  it is required.
132      */
133     protected PropertyType resolveType( PropertyType type )
134     {
135         if( type instanceof DeferredPropertyType )
136             {
137             type = ((DeferredPropertyType)type).resolveType( classRegistry );
138             return( type );
139             }
140         else if( type instanceof ContainerPropertyType )
141             {
142             ContainerPropertyType containerType = (ContainerPropertyType)type;
143             PropertyType valType = containerType.getValueType();
144             if( valType instanceof DeferredPropertyType )
145                 {
146                 valType = ((DeferredPropertyType)valType).resolveType( classRegistry );
147                 containerType = containerType.replaceContainedType( valType );
148                 return( containerType );
149                 }
150             }
151         return( null );
152     }
153 
154     /**
155      *  Resolves any deferred types against the class registry
156      *  associated with this meta-class.  This should be called
157      *  by meta-object implementations during instantiation until
158      *  a more automatic way becomes available.
159      */
160     public void resolveTypes()
161     {
162         if( resolved )
163             return;
164 
165         for( Iterator i = properties.entrySet().iterator(); i.hasNext(); )
166             {
167             Map.Entry entry = (Map.Entry)i.next();
168 
169             PropertyInfo info = (PropertyInfo)entry.getValue();
170             PropertyType type = info.getPropertyType();
171             PropertyType resolvedType = resolveType( type );
172             if( resolvedType == null )
173                 continue;
174 
175             // This might be bad since we currently allow different
176             // implementations of PropertyInfo.  I think that's wrong
177             // though, so may change in the future.  It only gets
178             // toolkits in trouble to try and implement it themselves...
179             // and indeed this section only breaks those improper uses.
180             info = info.replacePropertyType( resolvedType );
181             entry.setValue( info );
182             }
183 
184         resolved = true;
185     }
186 
187     /**
188      *  Returns the class registry to which this meta-class belongs.
189      */
190     public MetaClassRegistry getClassRegistry()
191     {
192         return( classRegistry );
193     }
194 
195     /**
196      *  Returns the name of this meta-class.
197      */
198     public String getName()
199     {
200         return( name );
201     }
202 
203     /**
204      *  Returns a List containing the immediate superclasses of this meta-class.
205      */
206     public List getSuperclasses()
207     {
208         return( Collections.unmodifiableList( superclasses ) );
209     }
210 
211     /**
212      *  Adds the specified property info to this meta-class.
213      */
214     protected void addProperty( PropertyInfo info )
215     {
216         String name = info.getPropertyName();
217         if( properties.containsKey( name ) )
218             {
219             // Check to make sure the types are compatable.  Use
220             // the most specific type.
221             PropertyInfo check = getPropertyInfo( name );
222 
223             // Right now we cheat.  Types have to be identical
224             // and we never replace.
225             if( !check.getPropertyType().equals( info.getPropertyType() ) )
226                 throw new RuntimeException( "Property already exists:" + name );
227             return;
228             }
229 
230         properties.put( name, info );
231     }
232 
233     /**
234      *  Returns the type for the specified property.
235      */
236     public PropertyType getPropertyType( String name )
237     {
238         PropertyInfo info = getPropertyInfo( name );
239         if( info == null )
240             return( null );
241         return( info.getPropertyType() );
242     }
243 
244     /**
245      *  Returns the descriptive information for the specified
246      *  property.
247      */
248     public PropertyInfo getPropertyInfo( String name )
249     {
250 // Temporary until class registry knows about dependencies
251 // May cause types to be resolved too early.
252 if( !resolved )
253     resolveTypes();
254         return( (PropertyInfo)properties.get( name ) );
255     }
256 
257     /**
258      *  Returns an iterator over all valid property names.
259      */
260     public Iterator propertyNames()
261     {
262         return( getPropertyNames().iterator() );
263     }
264 
265     /**
266      *  Returns the unmodifiable set of property names.
267      */
268     public Set getPropertyNames()
269     {
270         return( Collections.unmodifiableSet( properties.keySet() ) );
271     }
272 
273     /**
274      *  Returns an unmodifiable collection of property info objects.
275      */
276     public Collection getPropertyInfos()
277     {
278         return( Collections.unmodifiableCollection( properties.values() ) );
279     }
280 
281     /**
282      *  Returns true if the specified meta-object is an instance
283      *  of this class.
284      */
285     public boolean isInstance( MetaObject obj )
286     {
287         if( equals( obj.getMetaClass() ) )
288             return( true );
289 
290         // Check the superclasses
291         for( Iterator i = superclasses.iterator(); i.hasNext(); )
292             {
293             MetaClass mc = (MetaClass)i.next();
294             if( mc.isInstance(obj) )
295                 return( true );
296             }
297 
298         return( false );
299     }
300 
301     public int hashCode()
302     {
303         return( name.hashCode() );
304     }
305 
306     public boolean equals( MetaClass mClass )
307     {
308         if( mClass == this )
309             return( true );
310 
311         if( mClass == null )
312             return( false );
313         if( !name.equals( mClass.name ) )
314             return( false );
315         if( !properties.equals( mClass.properties ) )
316             return( false );
317         return( true );
318     }
319 
320     public boolean equals( Object obj )
321     {
322         if( obj == this )
323             return( true );
324 
325         if( obj instanceof MetaClass )
326             {
327             return( equals( (MetaClass)obj ) );
328             }
329         return( false );
330     }
331 
332     public String toString()
333     {
334         return( "MetaClass[" + name + "]" );
335     }
336 }