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
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
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
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
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 }