KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > net > axis > server > EntityBeanDeserializer


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7
8 // $Id: EntityBeanDeserializer.java,v 1.11.4.2 2005/03/02 14:19:51 tdiesler Exp $
9

10 package org.jboss.net.axis.server;
11
12 import org.jboss.axis.MessageContext;
13 import org.jboss.axis.description.TypeDesc;
14 import org.jboss.axis.encoding.DeserializationContext;
15 import org.jboss.axis.encoding.Deserializer;
16 import org.jboss.axis.encoding.DeserializerImpl;
17 import org.jboss.axis.encoding.Target;
18 import org.jboss.axis.encoding.TypeMapping;
19 import org.jboss.axis.encoding.ser.SimpleDeserializer;
20 import org.jboss.axis.message.SOAPHandler;
21 import org.jboss.axis.utils.JavaUtils;
22 import org.jboss.axis.utils.Messages;
23 import org.jboss.net.axis.ParameterizableDeserializer;
24 import org.xml.sax.Attributes JavaDoc;
25 import org.xml.sax.SAXException JavaDoc;
26
27 import javax.naming.InitialContext JavaDoc;
28 import javax.naming.NamingException JavaDoc;
29 import javax.xml.namespace.QName JavaDoc;
30 import java.beans.Introspector JavaDoc;
31 import java.beans.PropertyDescriptor JavaDoc;
32 import java.lang.reflect.InvocationTargetException JavaDoc;
33 import java.lang.reflect.Method JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.StringTokenizer JavaDoc;
39
40 /**
41  * Server-side deserializer hitting an existing entity bean. Derived
42  * from the axis BeanDeserializer. Currently relies on some
43  * silly conventions that must be configurable in the deployment
44  * descriptor.
45  * @author jung
46  * @created 21.03.2002
47  * @version $Revision: 1.11.4.2 $
48  */

49
50 public class EntityBeanDeserializer
51         extends DeserializerImpl
52         implements ParameterizableDeserializer
53 {
54
55    //
56
// Attributes
57
//
58

59    protected Map JavaDoc options;
60
61    protected Object JavaDoc home;
62    protected Method JavaDoc findMethod;
63    protected List JavaDoc findElements = new java.util.ArrayList JavaDoc(1);
64    protected Object JavaDoc[] findObjects;
65    protected TypeDesc typeDesc;
66    protected QName JavaDoc xmlType;
67    protected Class JavaDoc javaType;
68    protected Map JavaDoc propertyMap = new java.util.HashMap JavaDoc(4);
69    protected int collectionIndex = -1;
70    protected Collection JavaDoc fieldSetters = new java.util.ArrayList JavaDoc(4);
71    protected boolean initialized = false;
72
73    /**
74     * Construct a new BeanSerializer
75     * @param remoteType remote interface of the entity bean
76     * @param xmlType fully-qualified xml tag-name of the corresponding xml structure
77     */

78
79    public EntityBeanDeserializer(Class JavaDoc remoteType, QName JavaDoc xmlType)
80            throws Exception JavaDoc
81    {
82       // first the default constructor
83
this.xmlType = xmlType;
84       this.javaType = remoteType;
85    }
86
87    /** returns an option string with a default */
88    protected String JavaDoc getStringOption(String JavaDoc key, String JavaDoc def)
89    {
90       String JavaDoc value = (String JavaDoc)options.get(key);
91       if (value == null)
92       {
93          value = def;
94       }
95       return value;
96    }
97
98    /**
99     * initialize the deserializer
100     */

101
102    protected void initialize(MessageContext ctx) throws SAXException JavaDoc
103    {
104       if (!initialized)
105       {
106          initialized = true;
107
108          try
109          {
110             //
111
// Extract home from jndiName
112
//
113
this.home =
114                     new InitialContext JavaDoc().lookup(getStringOption("JndiName", javaType.getName() + "Home"));
115
116             //
117
// Extract find method from name and sig
118
//
119

120             String JavaDoc findMethodName = getStringOption("FindMethodName", "findByPrimaryKey");
121             String JavaDoc findMethodSignatureString =
122                     getStringOption("FindMethodSignature", "java.lang.String");
123             List JavaDoc findMethodSignatureClasses = new java.util.ArrayList JavaDoc(1);
124             StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(findMethodSignatureString, ";");
125             while (tokenizer.hasMoreTokens())
126             {
127                findMethodSignatureClasses.add(ctx.getClassLoader().loadClass(tokenizer.nextToken()));
128             }
129             this.findMethod =
130                     home.getClass().getMethod(findMethodName,
131                             (Class JavaDoc[])findMethodSignatureClasses.toArray(new Class JavaDoc[findMethodSignatureClasses.size()]));
132
133             //
134
// Do some reasonable preprocessing
135
//
136

137             // Get a list of the bean properties
138
BeanPropertyDescriptor[] pd = getPd(javaType);
139             // loop through properties and grab the names for later
140
for (int i = 0; i < pd.length; i++)
141             {
142                BeanPropertyDescriptor descriptor = pd[i];
143                propertyMap.put(descriptor.getName(), descriptor);
144                propertyMap.put(JavaUtils.xmlNameToJava(descriptor.getName()), descriptor);
145             }
146             typeDesc = TypeDesc.getTypeDescForClass(javaType);
147
148             //
149
// Next prepare the elements we need to call the finder
150
//
151

152             String JavaDoc findMethodElements = getStringOption("FindMethodElements", "name");
153             tokenizer = new StringTokenizer JavaDoc(findMethodElements, ";");
154             while (tokenizer.hasMoreElements())
155             {
156                if (typeDesc != null)
157                {
158                   this.findElements.add(typeDesc.getAttributeNameForField(tokenizer.nextToken()));
159                }
160                else
161                {
162                   this.findElements.add(new QName JavaDoc("", tokenizer.nextToken()));
163                }
164             }
165
166             this.findObjects = new Object JavaDoc[findElements.size()];
167          }
168          catch (NamingException JavaDoc e)
169          {
170             throw new SAXException JavaDoc("Could not lookup home.", e);
171          }
172          catch (ClassNotFoundException JavaDoc e)
173          {
174             throw new SAXException JavaDoc("Could not find signature class.", e);
175          }
176          catch (NoSuchMethodException JavaDoc e)
177          {
178             throw new SAXException JavaDoc("Could not find finder method.", e);
179          }
180
181       }
182    }
183
184    public void setOptions(Map JavaDoc options)
185    {
186       this.options = options;
187    }
188
189    public Map JavaDoc getOptions()
190    {
191       return options;
192    }
193
194    /**
195     * Deserializer interface called on each child element encountered in
196     * the XML stream.
197     * @param namespace is the namespace of the child element
198     * @param localName is the local name of the child element
199     * @param prefix is the prefix used on the name of the child element
200     * @param attributes are the attributes of the child element
201     * @param context is the deserialization context.
202     * @return is a Deserializer to use to deserialize a child (must be
203     * a derived class of SOAPHandler) or null if no deserialization should
204     * be performed.
205     */

206    public SOAPHandler onStartChild(String JavaDoc namespace,
207                                    String JavaDoc localName,
208                                    String JavaDoc prefix,
209                                    Attributes JavaDoc attributes,
210                                    DeserializationContext context)
211            throws SAXException JavaDoc
212    {
213       BeanPropertyDescriptor propDesc = null;
214
215       if (typeDesc != null)
216       {
217          QName JavaDoc elemQName = new QName JavaDoc(namespace, localName);
218          String JavaDoc fieldName = typeDesc.getFieldNameForElement(elemQName);
219          propDesc = (BeanPropertyDescriptor)propertyMap.get(fieldName);
220       }
221
222       if (propDesc == null)
223       {
224          // look for a field by this name.
225
propDesc = (BeanPropertyDescriptor)propertyMap.get(localName);
226       }
227       if (propDesc == null)
228       {
229          // look for a field by the "adjusted" name.
230
propDesc =
231                  (BeanPropertyDescriptor)propertyMap.get(JavaUtils.xmlNameToJava(localName));
232       }
233
234       if (propDesc == null)
235       {
236          // No such field
237
throw new SAXException JavaDoc(Messages.getMessage("badElem00", javaType.getName(), localName));
238       }
239
240       // Determine the QName for this child element.
241
// Look at the type attribute specified. If this fails,
242
// use the javaType of the property to get the type qname.
243
QName JavaDoc qn = context.getTypeFromAttributes(namespace, localName, attributes);
244
245       // get the deserializer
246
Deserializer dSer = context.getDeserializerForType(qn);
247
248       // If no deserializer, use the base DeserializerImpl.
249
// There may not be enough information yet to choose the
250
// specific deserializer.
251
if (dSer == null)
252       {
253          dSer = new DeserializerImpl();
254          // determine a default type for this child element
255
TypeMapping tm = context.getTypeMapping();
256          Class JavaDoc type = propDesc.getType();
257          dSer.setDefaultType(tm.getTypeQName(type));
258       }
259
260       QName JavaDoc elementQName = new QName JavaDoc(namespace, localName);
261       if (findElements.contains(elementQName))
262       {
263          dSer.registerValueTarget(new FindPropertyTarget(findElements.indexOf(elementQName)));
264       }
265       else if (propDesc.getWriteMethod().getParameterTypes().length == 1)
266       {
267          // Success! Register the target and deserializer.
268
collectionIndex = -1;
269          dSer.registerValueTarget(new BeanPropertyTarget(propDesc));
270       }
271       else
272       {
273          // Success! This is a collection of properties so use the index
274
collectionIndex++;
275          dSer.registerValueTarget(new BeanPropertyTarget(propDesc, collectionIndex));
276       }
277       return (SOAPHandler)dSer;
278    }
279
280    /**
281     * Set the bean properties that correspond to element attributes.
282     *
283     * This method is invoked after startElement when the element requires
284     * deserialization (i.e. the element is not an href and the value is not nil.)
285     * @param namespace is the namespace of the element
286     * @param localName is the name of the element
287     * @param qName is the prefixed qName of the element
288     * @param attributes are the attributes on the element...used to get the type
289     * @param context is the DeserializationContext
290     */

291    public void onStartElement(String JavaDoc namespace,
292                               String JavaDoc localName,
293                               String JavaDoc qName,
294                               Attributes JavaDoc attributes,
295                               DeserializationContext context)
296            throws SAXException JavaDoc
297    {
298
299       initialize(context.getMessageContext());
300
301       if (typeDesc == null)
302          return;
303
304       // loop through the attributes and set bean properties that
305
// correspond to attributes
306
for (int i = 0; i < attributes.getLength(); i++)
307       {
308          QName JavaDoc attrQName = new QName JavaDoc(attributes.getURI(i), attributes.getLocalName(i));
309          String JavaDoc fieldName = typeDesc.getFieldNameForAttribute(attrQName);
310          if (fieldName == null)
311             continue;
312
313          // look for the attribute property
314
BeanPropertyDescriptor bpd =
315                  (BeanPropertyDescriptor)propertyMap.get(fieldName);
316          if (bpd != null)
317          {
318             if (bpd.getWriteMethod() == null)
319                continue;
320
321             // determine the QName for this child element
322
TypeMapping tm = context.getTypeMapping();
323             Class JavaDoc type = bpd.getType();
324             QName JavaDoc qn = tm.getTypeQName(type);
325             if (qn == null)
326                throw new SAXException JavaDoc(Messages.getMessage("unregistered00", type.toString()));
327
328             // get the deserializer
329
Deserializer dSer = context.getDeserializerForType(qn);
330             if (dSer == null)
331                throw new SAXException JavaDoc(Messages.getMessage("noDeser00", type.toString()));
332             if (!(dSer instanceof SimpleDeserializer))
333                throw new SAXException JavaDoc(Messages.getMessage("AttrNotSimpleType00", bpd.getName(), type.toString()));
334
335             if (findElements.contains(attrQName))
336             {
337                dSer.registerValueTarget(new FindPropertyTarget(findElements.indexOf(attrQName)));
338             }
339             else if (bpd.getWriteMethod().getParameterTypes().length == 1)
340             {
341                // Success! Create an object from the string and set
342
// it in the bean
343
try
344                {
345                   Object JavaDoc val = ((SimpleDeserializer)dSer).makeValue(attributes.getValue(i));
346                   bpd.getWriteMethod().invoke(value, new Object JavaDoc[]{val});
347                }
348                catch (Exception JavaDoc e)
349                {
350                   throw new SAXException JavaDoc(e);
351                }
352             }
353
354          } // if
355
} // attribute loop
356
}
357
358    public void onEndElement(String JavaDoc namespace,
359                             String JavaDoc localName,
360                             DeserializationContext context)
361            throws SAXException JavaDoc
362    {
363       try
364       {
365          value = findMethod.invoke(home, findObjects);
366          Iterator JavaDoc allSetters = fieldSetters.iterator();
367          while (allSetters.hasNext())
368          {
369             ((BeanPropertyTarget)allSetters.next()).setReal(value);
370          }
371          fieldSetters = null;
372       }
373       catch (InvocationTargetException JavaDoc e)
374       {
375          throw new SAXException JavaDoc("Encountered exception " + e.getTargetException());
376       }
377       catch (IllegalAccessException JavaDoc e)
378       {
379          throw new SAXException JavaDoc("Encountered exception " + e);
380       }
381       super.onEndElement(namespace, localName, context);
382    }
383
384    public class FindPropertyTarget implements Target
385    {
386       int position;
387
388       public FindPropertyTarget(int index)
389       {
390          this.position = index;
391       }
392
393       public void set(Object JavaDoc value) throws SAXException JavaDoc
394       {
395          findObjects[position] = value;
396       }
397    }
398
399    /**
400     * Class which knows how to update a bean property
401     */

402    public class BeanPropertyTarget implements Target
403    {
404       private BeanPropertyDescriptor pd;
405       private int index = -1;
406       Object JavaDoc value;
407
408       /**
409        * This constructor is used for a normal property.
410        * @param pd is the property
411        **/

412       public BeanPropertyTarget(BeanPropertyDescriptor pd)
413       {
414          this.pd = pd;
415          this.index = -1; // disable indexing
416
}
417
418       /**
419        * This constructor is used for an indexed property.
420        * @param pd is the property
421        * @param i is the index
422        **/

423       public BeanPropertyTarget(BeanPropertyDescriptor pd, int i)
424       {
425          this.pd = pd;
426          this.index = i;
427       }
428
429       public void set(Object JavaDoc value) throws SAXException JavaDoc
430       {
431          this.value = value;
432          if (fieldSetters != null)
433          {
434             fieldSetters.add(this);
435          }
436          else
437          {
438             setReal(EntityBeanDeserializer.this.value);
439          }
440       }
441
442       public void setReal(Object JavaDoc target) throws SAXException JavaDoc
443       {
444          try
445          {
446             if (index < 0)
447                pd.getWriteMethod().invoke(target, new Object JavaDoc[]{value});
448             else
449                pd.getWriteMethod().invoke(target, new Object JavaDoc[]{new Integer JavaDoc(index), value});
450          }
451          catch (Exception JavaDoc e)
452          {
453             Class JavaDoc type = pd.getReadMethod().getReturnType();
454             value = JavaUtils.convert(value, type);
455             try
456             {
457                if (index < 0)
458                   pd.getWriteMethod().invoke(target, new Object JavaDoc[]{value});
459                else
460                   pd.getWriteMethod().invoke(target, new Object JavaDoc[]{new Integer JavaDoc(index), value});
461             }
462             catch (Exception JavaDoc ex)
463             {
464                throw new SAXException JavaDoc(ex);
465             }
466          }
467       }
468    }
469
470    static class BeanPropertyDescriptor
471    {
472       private String JavaDoc name;
473       private Method JavaDoc getter;
474       private Method JavaDoc setter;
475
476       public BeanPropertyDescriptor(String JavaDoc _name, Method JavaDoc _getter, Method JavaDoc _setter)
477       {
478          name = _name;
479          getter = _getter;
480          setter = _setter;
481       }
482
483       public Method JavaDoc getReadMethod()
484       {
485          return getter;
486       }
487
488       public Method JavaDoc getWriteMethod()
489       {
490          return setter;
491       }
492
493       public String JavaDoc getName()
494       {
495          return name;
496       }
497
498       public Class JavaDoc getType()
499       {
500          return getter.getReturnType();
501       }
502
503       /**
504        * This method attempts to sort the property descriptors to match the
505        * order defined in the class. This is necessary to support
506        * xsd:sequence processing, which means that the serialized order of
507        * properties must match the xml element order. (This method assumes that the
508        * order of the set methods matches the xml element order...the emitter
509        * will always order the set methods according to the xml order.)
510        *
511        * This routine also looks for set(i, type) and get(i) methods and adjusts the
512        * property to use these methods instead. These methods are generated by the
513        * emitter for "collection" of properties (i.e. maxOccurs="unbounded" on an element).
514        * JAX-RPC is silent on this issue, but web services depend on this kind of behaviour.
515        * The method signatures were chosen to match bean indexed properties.
516        */

517       static BeanPropertyDescriptor[] processPropertyDescriptors(PropertyDescriptor JavaDoc[] rawPd,
518                                                                  Class JavaDoc cls)
519       {
520          BeanPropertyDescriptor[] myPd = new BeanPropertyDescriptor[rawPd.length];
521
522          for (int i = 0; i < rawPd.length; i++)
523          {
524             myPd[i] =
525                     new BeanPropertyDescriptor(rawPd[i].getName(),
526                             rawPd[i].getReadMethod(),
527                             rawPd[i].getWriteMethod());
528          }
529
530          try
531          {
532             // Create a new pd array and index into the array
533
int index = 0;
534
535             // Build a new pd array
536
// defined by the order of the get methods.
537
BeanPropertyDescriptor[] newPd = new BeanPropertyDescriptor[rawPd.length];
538             Method JavaDoc[] methods = cls.getMethods();
539             for (int i = 0; i < methods.length; i++)
540             {
541                Method JavaDoc method = methods[i];
542                if (method.getName().startsWith("set"))
543                {
544                   boolean found = false;
545                   for (int j = 0; j < myPd.length && !found; j++)
546                   {
547                      if (myPd[j].getWriteMethod() != null
548                              && myPd[j].getWriteMethod().equals(method))
549                      {
550                         found = true;
551                         newPd[index] = myPd[j];
552                         index++;
553                      }
554                   }
555                }
556             }
557             // Now if there are any additional property descriptors, add them to the end.
558
if (index < myPd.length)
559             {
560                for (int m = 0; m < myPd.length && index < myPd.length; m++)
561                {
562                   boolean found = false;
563                   for (int n = 0; n < index && !found; n++)
564                   {
565                      found = (myPd[m] == newPd[n]);
566                   }
567                   if (!found)
568                   {
569                      newPd[index] = myPd[m];
570                      index++;
571                   }
572                }
573             }
574             // If newPd has same number of elements as myPd, use newPd.
575
if (index == myPd.length)
576             {
577                myPd = newPd;
578             }
579
580             // Get the methods of the class and look for the special set and
581
// get methods for property "collections"
582
for (int i = 0; i < methods.length; i++)
583             {
584                if (methods[i].getName().startsWith("set")
585                        && methods[i].getParameterTypes().length == 2)
586                {
587                   for (int j = 0; j < methods.length; j++)
588                   {
589                      if ((methods[j].getName().startsWith("get")
590                              || methods[j].getName().startsWith("is"))
591                              && methods[j].getParameterTypes().length == 1
592                              && methods[j].getReturnType() == methods[i].getParameterTypes()[1]
593                              && methods[j].getParameterTypes()[0] == int.class
594                              && methods[i].getParameterTypes()[0] == int.class)
595                      {
596                         for (int k = 0; k < myPd.length; k++)
597                         {
598                            if (myPd[k].getReadMethod() != null
599                                    && myPd[k].getWriteMethod() != null
600                                    && myPd[k].getReadMethod().getName().equals(methods[j].getName())
601                                    && myPd[k].getWriteMethod().getName().equals(methods[i].getName()))
602                            {
603                               myPd[k] = new BeanPropertyDescriptor(myPd[k].getName(), methods[j], methods[i]);
604                            }
605                         }
606                      }
607                   }
608                }
609             }
610          }
611          catch (Exception JavaDoc e)
612          {
613             // Don't process Property Descriptors if problems occur
614
return myPd;
615          }
616          return myPd;
617       }
618    }
619
620    /**
621     * Create a BeanPropertyDescriptor array for the indicated class.
622     */

623    public static BeanPropertyDescriptor[] getPd(Class JavaDoc javaType)
624    {
625       BeanPropertyDescriptor[] pd;
626       try
627       {
628          PropertyDescriptor JavaDoc[] rawPd =
629                  Introspector.getBeanInfo(javaType).getPropertyDescriptors();
630          pd = BeanPropertyDescriptor.processPropertyDescriptors(rawPd, javaType);
631       }
632       catch (Exception JavaDoc e)
633       {
634          // this should never happen
635
throw new RuntimeException JavaDoc(e.getMessage());
636       }
637       return pd;
638    }
639
640 }
Popular Tags