View Javadoc

1   package org.codehaus.xfire.type.basic;
2   
3   import java.beans.BeanInfo;
4   import java.beans.IntrospectionException;
5   import java.beans.Introspector;
6   import java.beans.PropertyDescriptor;
7   import java.lang.reflect.InvocationTargetException;
8   
9   import org.codehaus.xfire.MessageContext;
10  import org.codehaus.xfire.XFireRuntimeException;
11  import org.codehaus.xfire.fault.XFireFault;
12  import org.codehaus.xfire.message.MessageReader;
13  import org.codehaus.xfire.message.MessageWriter;
14  import org.codehaus.xfire.soap.SoapConstants;
15  import org.codehaus.xfire.type.Type;
16  import org.codehaus.xfire.util.NamespaceHelper;
17  import org.dom4j.Element;
18  import org.dom4j.Namespace;
19  
20  /***
21   * Serializes JavaBeans.
22   * 
23   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
24   */
25  public class BeanType
26      extends Type
27  {
28      public Object readObject(MessageReader reader, MessageContext context)
29          throws XFireFault
30      {
31          try
32          {
33              Class clazz = getTypeClass();
34              Object object = clazz.newInstance();
35              
36              BeanInfo info = Introspector.getBeanInfo( clazz, Object.class );
37              
38              PropertyDescriptor[] pds = info.getPropertyDescriptors();
39              
40              while( reader.hasMoreChildReaders() )
41              {
42                  MessageReader childReader = reader.getNextChildReader();
43                  String name = childReader.getLocalName();
44                  
45                  PropertyDescriptor pd = findPropertyDescriptor( name, pds );
46                  
47                  if ( pd == null )
48                      throw new XFireRuntimeException( "Couldn't find property for " + name );
49                      
50                  Type type = getTypeMapping().getType( pd.getPropertyType() );
51  
52                  if ( type == null )
53                      throw new XFireRuntimeException( "Couldn't find type for " 
54                              + pd.getPropertyType() + " for property " + name );
55  
56                  Object writeObj = type.readObject( childReader, context );
57                  
58                  pd.getWriteMethod().invoke( object , new Object[] { writeObj } );
59              }
60              
61              return object;
62          }
63          catch (IntrospectionException e)
64          {
65              throw new XFireFault("Couldn't introspect.", e, XFireFault.RECEIVER);
66          }
67          catch (IllegalArgumentException e)
68          {
69              throw new XFireFault("Illegal argument to service.", e, XFireFault.RECEIVER);
70          } 
71          catch (IllegalAccessException e)
72          {
73              throw new XFireFault("Illegal access.", e, XFireFault.RECEIVER);
74          }
75          catch (InvocationTargetException e)
76          {
77              throw new XFireFault("Couldn't invoke the service.", e, XFireFault.SENDER);
78          }
79  		catch (InstantiationException e)
80  		{
81              throw new XFireFault("Couldn't instantiate service.", e, XFireFault.SENDER);
82  		}
83      }
84  
85      protected PropertyDescriptor findPropertyDescriptor(String name, PropertyDescriptor[] pd)
86      {
87          for ( int i = 0; i < pd.length; i++ )
88          {
89              if ( pd[i].getName().equals(name) )
90                  return pd[i];
91          }
92          return null;
93      }
94  
95      /***
96       * @see org.codehaus.xfire.type.Type#writeObject(java.lang.Object)
97       */
98      public void writeObject(Object object, MessageWriter writer, MessageContext context)
99          throws XFireFault
100     {
101         if (object == null)
102             return;
103         
104         try
105         {
106         	// TODO: could be an exception as well.
107             BeanInfo info = Introspector.getBeanInfo( getTypeClass(), Object.class );
108             
109             PropertyDescriptor[] pd = info.getPropertyDescriptors();
110             
111             for ( int i = 0; i < pd.length; i++ )
112             {
113                 Class typeClass = pd[i].getPropertyType();
114                 Type type = getTypeMapping().getType( typeClass );
115 
116                 if ( type == null )
117                     throw new XFireRuntimeException( "Couldn't find type for " + typeClass + " for property " + pd[i].getName() );
118 
119                 MessageWriter cwriter = writer.getChildWriter( pd[i].getName(), 
120                                                                getSchemaType().getNamespaceURI() );
121                 type.writeObject( pd[i].getReadMethod().invoke( object , new Object[0] ),
122                                   cwriter, 
123                                   context );
124                 cwriter.close();
125             }
126         }
127         catch (IntrospectionException e)
128         {
129             throw new XFireRuntimeException("Couldn't introspect.", e);
130         }
131         catch (IllegalArgumentException e)
132         {
133             throw new XFireRuntimeException("Illegal argument.", e);
134         } 
135         catch (IllegalAccessException e)
136         {
137             throw new XFireRuntimeException("Illegal access.", e);
138         }
139         catch (InvocationTargetException e)
140         {
141             // TODO: remember ITEs can go funny sometimes...
142             throw new XFireRuntimeException("Couldn't invoke.", e);
143         }
144     }
145 
146     /***
147      * @see org.codehaus.xfire.type.Type#writeSchema()
148      */
149     public void writeSchema( Element root )
150     {
151         try
152         {
153             // TODO: this bean could be an exception as well.
154             BeanInfo info = Introspector.getBeanInfo( getTypeClass(), Object.class );
155             
156             Namespace xsdNs = root.getNamespaceForURI( SoapConstants.XSD );
157             org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs); 
158             
159             Element complex = root.addElement( complexQ );
160             
161             complex.addAttribute( "name", this.getSchemaType().getLocalPart() );
162 
163             org.dom4j.QName seqQ = new org.dom4j.QName("sequence", xsdNs); 
164             Element seq = complex.addElement( seqQ );
165             
166             PropertyDescriptor[] pd = info.getPropertyDescriptors();
167             
168             org.dom4j.QName elementQ = new org.dom4j.QName("element", xsdNs); 
169             
170             for ( int i = 0; i < pd.length; i++ )
171             {
172                 Class typeClass = pd[i].getPropertyType();
173                 
174                 Element element = seq.addElement( elementQ );
175                 
176                 Type type = getTypeMapping().getType( typeClass );
177                 
178                 Namespace typeNS = NamespaceHelper.getNamespace( root, type.getSchemaType().getNamespaceURI() );
179                 
180                 element.addAttribute( "name", pd[i].getDisplayName() );
181                 // TODO: Add config support for nillable
182                 element.addAttribute( "nillable", "true" );
183                 element.addAttribute("type", typeNS.getPrefix() + ":" + type.getSchemaType().getLocalPart());
184             }
185         }
186         catch (IntrospectionException e)
187         {
188             throw new XFireRuntimeException("Couldn't introspect.", e);
189         }
190         catch (IllegalArgumentException e)
191         {
192             throw new XFireRuntimeException("Illegal argument.", e);
193         } 
194     }
195     
196     /***
197      * We need to write a complex type schema for Beans, so return true.
198      * 
199      * @see org.codehaus.xfire.type.Type#isComplex()
200      */
201     public boolean isComplex()
202     {
203         return true;
204     }
205 }