KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xb > binding > MetadataDrivenObjectModelFactory


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

7 package org.jboss.xb.binding;
8
9 import org.jboss.xb.binding.metadata.unmarshalling.BasicElementBinding;
10 import org.jboss.xb.binding.metadata.unmarshalling.ElementBinding;
11 import org.jboss.xb.binding.metadata.unmarshalling.XmlValueBinding;
12 import org.jboss.xb.binding.metadata.unmarshalling.XmlValueContainer;
13 import org.jboss.xb.binding.metadata.unmarshalling.AttributeBinding;
14 import org.jboss.logging.Logger;
15 import org.xml.sax.Attributes JavaDoc;
16
17 import javax.xml.namespace.QName JavaDoc;
18 import java.util.Collection JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.HashSet JavaDoc;
21 import java.util.Set JavaDoc;
22 import java.lang.reflect.Constructor JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25
26 /**
27  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
28  * @version <tt>$Revision: 1.1.2.1 $</tt>
29  */

30 public class MetadataDrivenObjectModelFactory
31    implements GenericObjectModelFactory
32 {
33    private static final Logger log = Logger.getLogger(MetadataDrivenObjectModelFactory.class);
34
35    public Object JavaDoc newChild(Object JavaDoc parent,
36                           UnmarshallingContext ctx,
37                           String JavaDoc namespaceURI,
38                           String JavaDoc localName,
39                           Attributes JavaDoc attrs)
40    {
41       boolean trace = log.isTraceEnabled();
42       if(trace)
43       {
44          log.trace("newChild " + namespaceURI + ":" + localName + " for " + parent);
45       }
46
47       Object JavaDoc child;
48
49       ElementBinding metadata = (ElementBinding)ctx.getMetadata();
50       if(metadata == null)
51       {
52          throw new JBossXBRuntimeException(
53             "Binding metadata is not available for element {" + namespaceURI + ":" + localName + "}"
54          );
55       }
56
57       if(Collection JavaDoc.class.isAssignableFrom(metadata.getJavaType()))
58       {
59          Collection JavaDoc col;
60          if(parent instanceof Immutable)
61          {
62             Immutable imm = (Immutable)parent;
63             col = (Collection JavaDoc)imm.getChild(localName);
64             if(col == null)
65             {
66                col = (Collection JavaDoc)newInstance(metadata);
67                imm.addChild(localName, col);
68             }
69          }
70          else
71          {
72             col = (Collection JavaDoc)getFieldValue(metadata, parent);
73             if(col == null)
74             {
75                col = (Collection JavaDoc)newInstance(metadata);
76                setFieldValue(metadata.getName(), metadata.getField(), metadata.getSetter(), parent, col);
77             }
78          }
79
80          child = col;
81       }
82       else if(!Util.isAttributeType(metadata.getJavaType()))
83       {
84          child = newInstance(metadata);
85          if(!(child instanceof Immutable))
86          {
87             if(parent instanceof Collection JavaDoc)
88             {
89                ((Collection JavaDoc)parent).add(child);
90             }
91             else if(parent instanceof Immutable)
92             {
93                ((Immutable)parent).addChild(localName, child);
94             }
95             else if(metadata.getFieldType() != null && Collection JavaDoc.class.isAssignableFrom(metadata.getFieldType()))
96             {
97                Collection JavaDoc col = (Collection JavaDoc)getFieldValue(metadata, parent);
98                if(col == null)
99                {
100                   if(Set JavaDoc.class.isAssignableFrom(metadata.getFieldType()))
101                   {
102                      col = new HashSet JavaDoc();
103                   }
104                   else
105                   {
106                      col = new ArrayList JavaDoc();
107                   }
108                   setFieldValue(metadata.getName(), metadata.getField(), metadata.getSetter(), parent, col);
109                }
110                col.add(child);
111             }
112             else
113             {
114                setFieldValue(metadata.getName(), metadata.getField(), metadata.getSetter(), parent, child);
115             }
116          }
117
118          if(attrs != null && attrs.getLength() > 0)
119          {
120             for(int i = 0; i < attrs.getLength(); ++i)
121             {
122                QName JavaDoc attrName = new QName JavaDoc(attrs.getURI(i), attrs.getLocalName(i));
123                AttributeBinding attrBinding = metadata.getAttribute(attrName);
124                if(attrBinding != null)
125                {
126                   Object JavaDoc unmarshalledValue = SimpleTypeBindings.unmarshal(attrs.getValue(i),
127                      attrBinding.getJavaType()
128                   );
129
130                   if(child instanceof Immutable)
131                   {
132                      ((Immutable)child).addChild(attrName.getLocalPart(), unmarshalledValue);
133                   }
134                   else
135                   {
136                      setFieldValue(attrBinding.getAttributeName(),
137                         attrBinding.getField(),
138                         attrBinding.getSetter(),
139                         child,
140                         unmarshalledValue
141                      );
142                   }
143                }
144             }
145          }
146       }
147       else
148       {
149          child = null;
150       }
151
152       return child;
153    }
154
155    public void addChild(Object JavaDoc parent, Object JavaDoc child, UnmarshallingContext ctx, String JavaDoc namespaceURI, String JavaDoc localName)
156    {
157       if(child instanceof Immutable)
158       {
159          ElementBinding metadata = (ElementBinding)ctx.getMetadata();
160
161          child = ((Immutable)child).newInstance();
162          if(parent instanceof Collection JavaDoc)
163          {
164             ((Collection JavaDoc)parent).add(child);
165          }
166          else if(metadata.getFieldType() == null || Collection JavaDoc.class.isAssignableFrom(metadata.getFieldType()))
167          {
168             Collection JavaDoc col;
169             if(parent instanceof Immutable)
170             {
171                Immutable imm = (Immutable)parent;
172                col = (Collection JavaDoc)imm.getChild(localName);
173                if(col == null)
174                {
175                   col = new ArrayList JavaDoc();
176                   imm.addChild(localName, col);
177                }
178             }
179             else
180             {
181                col = (Collection JavaDoc)getFieldValue(metadata, parent);
182                if(col == null)
183                {
184                   col = new ArrayList JavaDoc();
185                   setFieldValue(metadata.getName(), metadata.getField(), metadata.getSetter(), parent, col);
186                }
187             }
188
189             col.add(child);
190          }
191          else if(parent instanceof Immutable)
192          {
193             ((Immutable)parent).addChild(localName, child);
194          }
195          else
196          {
197             setFieldValue(metadata.getName(), metadata.getField(), metadata.getSetter(), parent, child);
198          }
199       }
200    }
201
202    public void setValue(Object JavaDoc o, UnmarshallingContext ctx, String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc value)
203    {
204       ElementBinding metadata = (ElementBinding)ctx.getMetadata();
205
206       // todo: this check is a hack! undeterminism when field is of type collection and there is only RuntimeDocumentBinding
207
if(Collection JavaDoc.class.isAssignableFrom(metadata.getJavaType()))
208       {
209          ((Collection JavaDoc)o).add(value);
210       }
211       else
212       {
213          if(Util.isAttributeType(metadata.getJavaType()))
214          {
215             Object JavaDoc unmarshalledValue = SimpleTypeBindings.unmarshal(value, metadata.getJavaType());
216             if(o instanceof Collection JavaDoc)
217             {
218                ((Collection JavaDoc)o).add(unmarshalledValue);
219             }
220             else if(o instanceof Immutable)
221             {
222                ((Immutable)o).addChild(localName, unmarshalledValue);
223             }
224             else
225             {
226                if(Collection JavaDoc.class.isAssignableFrom(metadata.getFieldType()))
227                {
228                   Collection JavaDoc col = (Collection JavaDoc)getFieldValue(metadata, o);
229                   if(col == null)
230                   {
231                      col = new ArrayList JavaDoc();
232                      setFieldValue(metadata.getName(), metadata.getField(), metadata.getSetter(), o, col);
233                   }
234                   col.add(unmarshalledValue);
235                }
236                else
237                {
238                   setFieldValue(metadata.getName(), metadata.getField(), metadata.getSetter(), o, unmarshalledValue);
239                }
240             }
241          }
242          else
243          {
244             XmlValueBinding valueBinding = metadata.getValue();
245             if(valueBinding == null)
246             {
247                throw new JBossXBRuntimeException(
248                   "Required value binding is not customized for " + metadata.getName() + ": value=" + value
249                );
250             }
251
252             unmarshalValue(valueBinding, value, o);
253          }
254       }
255    }
256
257    public Object JavaDoc newRoot(Object JavaDoc root,
258                          UnmarshallingContext ctx,
259                          String JavaDoc namespaceURI,
260                          String JavaDoc localName,
261                          Attributes JavaDoc attrs)
262    {
263       if(root == null)
264       {
265          BasicElementBinding metadata = (BasicElementBinding)ctx.getMetadata();
266          if(metadata == null)
267          {
268             throw new JBossXBRuntimeException(
269                "Binding metadata is not available for top-level element {" + namespaceURI + ":" + localName + "}"
270             );
271          }
272          root = newInstance(metadata);
273       }
274       return root;
275    }
276
277    public Object JavaDoc completeRoot(Object JavaDoc root, UnmarshallingContext ctx, String JavaDoc namespaceURI, String JavaDoc localName)
278    {
279       return root instanceof Immutable ? ((Immutable)root).newInstance() : root;
280    }
281
282    // Private
283

284    private static void unmarshalValue(XmlValueBinding valueBinding, String JavaDoc value, Object JavaDoc o)
285    {
286       Object JavaDoc unmarshalled;
287       if(valueBinding.getValue() != null)
288       {
289          unmarshalled = newInstance(valueBinding);
290          unmarshalValue(valueBinding.getValue(), value, unmarshalled);
291
292          if(unmarshalled instanceof Immutable)
293          {
294             unmarshalled = ((Immutable)unmarshalled).newInstance();
295          }
296       }
297       else
298       {
299          unmarshalled = SimpleTypeBindings.unmarshal(value, valueBinding.getJavaType());
300       }
301
302       // todo o instanceof java.util.Collection?
303
if(o instanceof Immutable)
304       {
305          ((Immutable)o).addChild(valueBinding.getName().getLocalPart(), unmarshalled);
306       }
307       else
308       {
309          setFieldValue(valueBinding.getName(),
310             valueBinding.getField(),
311             valueBinding.getSetter(),
312             o,
313             unmarshalled
314          );
315       }
316    }
317
318    private static final void setFieldValue(QName JavaDoc elementName,
319                                            Field JavaDoc field,
320                                            Method JavaDoc setter,
321                                            Object JavaDoc parent,
322                                            Object JavaDoc child)
323    {
324       if(setter != null)
325       {
326          try
327          {
328             setter.invoke(parent, new Object JavaDoc[]{child});
329          }
330          catch(Exception JavaDoc e)
331          {
332             throw new JBossXBRuntimeException("Failed to set value (" +
333                child.getClass().getName() +
334                ":" +
335                child +
336                ") using setter " +
337                setter.getName() +
338                " in (" +
339                parent.getClass() +
340                ":" +
341                parent + "): " + e.getMessage(), e
342             );
343          }
344       }
345       else if(field != null)
346       {
347          try
348          {
349             field.set(parent, child);
350          }
351          catch(IllegalAccessException JavaDoc e)
352          {
353             throw new JBossXBRuntimeException("Illegal access exception setting value (" +
354                child.getClass() +
355                ":" +
356                child +
357                ") using field " +
358                field.getName() +
359                " in (" +
360                parent.getClass() +
361                ":" +
362                parent + "): " + e.getMessage(), e
363             );
364          }
365       }
366       else
367       {
368          throw new JBossXBRuntimeException("Element/attribute " +
369             elementName +
370             " is not bound to any field!"
371          );
372       }
373    }
374
375    private static final Object JavaDoc getFieldValue(ElementBinding metadata, Object JavaDoc parent)
376    {
377       Object JavaDoc value;
378       if(metadata.getGetter() != null)
379       {
380          try
381          {
382             value = metadata.getGetter().invoke(parent, null);
383          }
384          catch(Exception JavaDoc e)
385          {
386             throw new JBossXBRuntimeException("Failed to get value using getter " +
387                metadata.getGetter().getName() +
388                " from " +
389                parent.getClass() +
390                ":" +
391                parent + ": " + e.getMessage(), e
392             );
393          }
394       }
395       else if(metadata.getField() != null)
396       {
397          try
398          {
399             value = metadata.getField().get(parent);
400          }
401          catch(IllegalAccessException JavaDoc e)
402          {
403             throw new JBossXBRuntimeException("Illegal access exception getting value using field " +
404                metadata.getField().getName() +
405                " from " +
406                parent.getClass() +
407                ":" +
408                parent + ": " + e.getMessage(), e
409             );
410          }
411       }
412       else
413       {
414          throw new JBossXBRuntimeException("Element " +
415             metadata.getName() +
416             " is not bound to any field!"
417          );
418       }
419
420       return value;
421    }
422
423    private static final Object JavaDoc newInstance(XmlValueContainer metadata)
424    {
425       boolean trace = log.isTraceEnabled();
426
427       Object JavaDoc instance;
428       Class JavaDoc javaType = metadata.getJavaType();
429       if(trace)
430       {
431          log.trace("newInstance " + javaType + " for " + metadata.getName());
432       }
433       try
434       {
435          Constructor JavaDoc ctor = javaType.getConstructor(null);
436          instance = ctor.newInstance(null);
437       }
438       catch(NoSuchMethodException JavaDoc e)
439       {
440          instance = new Immutable(javaType);
441       }
442       catch(Exception JavaDoc e)
443       {
444          throw new JBossXBRuntimeException(
445             "Failed to create an instance of " + metadata.getName() + " of type " + metadata.getJavaType()
446          );
447       }
448       if(trace)
449       {
450          log.trace("newInstance=" + instance);
451       }
452       return instance;
453    }
454 }
455
Popular Tags