KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xb > binding > group > ValueListHandler


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.xb.binding.group;
23
24 import java.lang.reflect.Constructor JavaDoc;
25 import java.lang.reflect.Array JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30
31 import org.jboss.util.Classes;
32 import org.jboss.xb.binding.GenericValueContainer;
33 import org.jboss.xb.binding.JBossXBRuntimeException;
34 import org.jboss.xb.binding.sunday.unmarshalling.AttributeBinding;
35 import org.jboss.xb.binding.sunday.unmarshalling.AttributeHandler;
36 import org.jboss.xb.binding.sunday.unmarshalling.CharactersHandler;
37 import org.jboss.xb.binding.sunday.unmarshalling.ElementBinding;
38 import org.jboss.xb.binding.sunday.unmarshalling.ParticleBinding;
39 import org.jboss.xb.binding.sunday.unmarshalling.ParticleHandler;
40 import org.jboss.xb.binding.sunday.unmarshalling.TermBinding;
41
42 /**
43  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
44  * @version <tt>$Revision: 2045 $</tt>
45  */

46 public interface ValueListHandler
47 {
48    ValueListHandler IMMUTABLE = new ValueListHandler()
49    {
50       public Object JavaDoc newInstance(ParticleBinding particle, ValueList valueList)
51       {
52          Class JavaDoc cls = valueList.getTargetClass();
53          Map JavaDoc map = valueList.getNonRequiredValues();
54
55          Collection JavaDoc values = map.values();
56          if(values.isEmpty())
57          {
58             throw new JBossXBRuntimeException("Value list does not contain non-required values.");
59          }
60
61          Constructor JavaDoc ctor = null;
62          Constructor JavaDoc[] ctors = cls.getConstructors();
63
64          if(ctors == null || ctors.length == 0)
65          {
66             throw new JBossXBRuntimeException("The class has no declared constructors: " + cls);
67          }
68
69          for(int i = 0; i < ctors.length; ++i)
70          {
71             Class JavaDoc[] types = ctors[i].getParameterTypes();
72
73             if(types == null || types.length == 0)
74             {
75                throw new IllegalStateException JavaDoc("Found no-arg constructor for immutable " + cls);
76             }
77
78             if(types.length == map.size())
79             {
80                ctor = ctors[i];
81
82                int typeInd = 0;
83                Iterator JavaDoc iter = values.iterator();
84                while(iter.hasNext())
85                {
86                   Class JavaDoc type = types[typeInd++];
87                   if(type.isPrimitive())
88                   {
89                      type = Classes.getPrimitiveWrapper(type);
90                   }
91
92                   if(!type.isAssignableFrom(iter.next().getClass()))
93                   {
94                      ctor = null;
95                      break;
96                   }
97                }
98
99                if(ctor != null)
100                {
101                   break;
102                }
103             }
104          }
105
106          if(ctor == null)
107          {
108             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
109             buf.append("There is no ctor in ")
110                .append(cls)
111                .append(" that would take the following arguments:\n");
112             int cnt = 0;
113             for(Iterator JavaDoc i = values.iterator(); i.hasNext();)
114             {
115                Object JavaDoc o = i.next();
116                buf.append(' ').append(++cnt).append(") ").append(o.getClass()).append(": ").append(o).append('\n');
117             }
118             throw new IllegalStateException JavaDoc(buf.toString());
119          }
120
121          try
122          {
123             return ctor.newInstance(values.toArray());
124          }
125          catch(Exception JavaDoc e)
126          {
127             throw new IllegalStateException JavaDoc("Failed to create immutable instance of " +
128                cls +
129                " using arguments: "
130                + values + ": " + e.getMessage()
131             );
132          }
133       }
134    };
135
136    ValueListHandler NON_DEFAULT_CTOR = new ValueListHandler()
137    {
138       public Object JavaDoc newInstance(ParticleBinding particle, ValueList valueList)
139       {
140          Class JavaDoc cls = valueList.getTargetClass();
141          int size = valueList.size();
142
143          if(size == 0)
144          {
145             try
146             {
147                return newInstance(cls.getConstructor(null), null);
148             }
149             catch(NoSuchMethodException JavaDoc e)
150             {
151                throw new JBossXBRuntimeException(
152                   "Value list does not contain non-required values and there is no no-arg ctor in " + cls
153                );
154             }
155          }
156
157          Constructor JavaDoc ctor = matchBestCtor(cls, valueList);
158
159          if(ctor == null)
160          {
161             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
162             buf.append("Failed to find no-arg ctor or best-match ctor in ")
163                .append(cls)
164                .append(", property values:\n");
165             int cnt = 0;
166             for(int i = 0; i < size; ++i)
167             {
168                Object JavaDoc o = valueList.getValue(i).value;
169                buf.append(' ').append(++cnt).append(") ").append(o).append('\n');
170             }
171             throw new JBossXBRuntimeException(buf.toString());
172          }
173
174          Object JavaDoc o;
175          int argsTotal = ctor.getParameterTypes().length;
176          if(argsTotal == size)
177          {
178             Object JavaDoc[] args = getArgs(ctor, valueList);
179             o = newInstance(ctor, args);
180          }
181          else
182          {
183             Object JavaDoc[] args = getArgs(ctor, valueList);
184             o = newInstance(ctor, args);
185
186             int i = argsTotal;
187             while(i < size)
188             {
189                ValueList.NonRequiredValue valueEntry = valueList.getValue(i++);
190                Object JavaDoc binding = valueEntry.binding;
191                if(binding instanceof ParticleBinding)
192                {
193                   Object JavaDoc handler = valueEntry.handler;
194                   ParticleBinding childParticle = (ParticleBinding)binding;
195                   if(handler instanceof ParticleHandler)
196                   {
197                      ParticleHandler pHandler = (ParticleHandler)handler;
198                      if(childParticle.isRepeatable())
199                      {
200                         TermBinding term = childParticle.getTerm();
201                         if(!(o instanceof GenericValueContainer) &&
202                               term.getAddMethodMetaData() == null &&
203                               term.getMapEntryMetaData() == null &&
204                               term.getPutMethodMetaData() == null)
205                         {
206                            pHandler.setParent(o, valueEntry.value, valueEntry.qName, childParticle, particle);
207                         }
208                         else
209                         {
210                            Collection JavaDoc col = (Collection JavaDoc)valueEntry.value;
211                            for(Iterator JavaDoc iter = col.iterator(); iter.hasNext();)
212                            {
213                               pHandler.setParent(o, iter.next(), valueEntry.qName, childParticle, particle);
214                            }
215                         }
216                      }
217                      else
218                      {
219                         pHandler.setParent(o, valueEntry.value, valueEntry.qName, childParticle, particle);
220                      }
221                   }
222                   else
223                   {
224                      ((CharactersHandler)handler).setValue(valueEntry.qName,
225                         (ElementBinding)childParticle.getTerm(),
226                         o,
227                         valueEntry.value
228                      );
229                   }
230                }
231                else if(binding instanceof AttributeBinding)
232                {
233                   AttributeBinding attr = (AttributeBinding)binding;
234                   AttributeHandler handler = attr.getHandler();
235                   if(handler != null)
236                   {
237                      handler.attribute(valueEntry.qName, attr.getQName(), attr, o, valueEntry.value);
238                   }
239                   else
240                   {
241                      throw new JBossXBRuntimeException("Attribute binding present but has no handler: element=" +
242                         valueEntry.qName +
243                         ", attrinute=" +
244                         attr.getQName()
245                      );
246                   }
247                }
248                else
249                {
250                   throw new JBossXBRuntimeException("Unexpected binding type: " + binding);
251                }
252             }
253          }
254
255          return o;
256       }
257
258       private Constructor JavaDoc matchBestCtor(Class JavaDoc cls, ValueList valueList)
259       {
260          Constructor JavaDoc bestMatch = null;
261          int bestMatchArgsTotal = 0;
262          Constructor JavaDoc[] ctors = cls.getConstructors();
263          int size = valueList.size();
264
265          for(int i = 0; i < ctors.length; ++i)
266          {
267             Constructor JavaDoc ctor = ctors[i];
268             Class JavaDoc[] types = ctor.getParameterTypes();
269
270             if((types == null || types.length == 0) && bestMatch == null)
271             {
272                bestMatch = ctor;
273                continue;
274             }
275
276             if(bestMatchArgsTotal <= types.length)
277             {
278                int typeInd = 0;
279                for(int valueInd = 0; typeInd < types.length && valueInd < size; ++typeInd, ++valueInd)
280                {
281                   Class JavaDoc type = types[typeInd];
282                   if(type.isPrimitive())
283                   {
284                      type = Classes.getPrimitiveWrapper(type);
285                   }
286
287                   ValueList.NonRequiredValue valueEntry = valueList.getValue(valueInd);
288                   Object JavaDoc value = valueEntry.value;
289                   if(value != null &&
290                      !(type.isAssignableFrom(value.getClass()) ||
291                      // if particle is repeatable and the type is array of a specific collection
292
// then we assume we can convert the arg later at creation time
293
// todo this code should be smarter
294
valueEntry.binding instanceof ParticleBinding &&
295                      ((ParticleBinding)valueEntry.binding).isRepeatable() &&
296                      type.isArray()
297                      ))
298                   {
299                      break;
300                   }
301
302                   if(bestMatchArgsTotal == types.length &&
303                      !bestMatch.getParameterTypes()[typeInd].isAssignableFrom(type))
304                   {
305                      break;
306                   }
307                }
308
309                if(typeInd == types.length)
310                {
311                   bestMatch = ctor;
312                   bestMatchArgsTotal = types.length;
313                }
314             }
315          }
316          return bestMatch;
317       }
318
319       private Object JavaDoc newInstance(Constructor JavaDoc bestMatch, Object JavaDoc[] args)
320       {
321          try
322          {
323             return bestMatch.newInstance(args);
324          }
325          catch(Exception JavaDoc e)
326          {
327             throw new JBossXBRuntimeException("Failed to create an instance of " +
328                bestMatch.getDeclaringClass() +
329                " using the following ctor arguments " +
330                Arrays.asList(args), e
331             );
332          }
333       }
334
335       private Object JavaDoc[] getArgs(Constructor JavaDoc ctor, ValueList valueList)
336       {
337          Class JavaDoc[] types = ctor.getParameterTypes();
338          Object JavaDoc[] args = new Object JavaDoc[types.length];
339          for(int i = 0; i < types.length; ++i)
340          {
341             ValueList.NonRequiredValue valueEntry = valueList.getValue(i);
342             Object JavaDoc arg = valueEntry.value;
343             if(valueEntry.value != null && !types[i].isAssignableFrom(arg.getClass()))
344             {
345                // if type is array then convert collection to array
346
// todo this part should be smarter about collections
347
if(types[i].isArray() && Collection JavaDoc.class.isAssignableFrom(arg.getClass()))
348                {
349                   Collection JavaDoc col = (Collection JavaDoc)arg;
350                   arg = Array.newInstance(types[i].getComponentType(), col.size());
351                   int arrInd = 0;
352                   for(Iterator JavaDoc iter = col.iterator(); iter.hasNext();)
353                   {
354                      Array.set(arg, arrInd++, iter.next());
355                   }
356                }
357             }
358             args[i] = arg;
359          }
360          return args;
361       }
362    };
363
364    class FACTORY
365    {
366       /**
367        * Collects children and adds them all at the time the newInstance is called.
368        *
369        * @param parent the parent object
370        * @return the parent object
371        */

372       public static ValueListHandler lazy(final Object JavaDoc parent)
373       {
374          return new ValueListHandler()
375          {
376             private final ValueList parentValueList = parent instanceof ValueList ? (ValueList)parent : null;
377             
378             public Object JavaDoc newInstance(ParticleBinding particle, ValueList valueList)
379             {
380                for(int i = 0; i < valueList.size(); ++i)
381                {
382                   ValueList.NonRequiredValue valueEntry = valueList.getValue(i);
383                   Object JavaDoc binding = valueEntry.binding;
384                   if(binding instanceof ParticleBinding)
385                   {
386                      Object JavaDoc handler = valueEntry.handler;
387                      ParticleBinding childParticle = (ParticleBinding)binding;
388                      if(handler instanceof ParticleHandler)
389                      {
390                         ParticleHandler pHandler = (ParticleHandler)handler;
391                         if(childParticle.isRepeatable())
392                         {
393                            if(parentValueList != null)
394                            {
395                               parentValueList.addTermValue(valueEntry.qName, childParticle, pHandler, valueEntry.value, null);
396                            }
397                            else
398                            {
399                               Collection JavaDoc col = (Collection JavaDoc) valueEntry.value;
400                               //System.out.println("newInstance: " + childParticle.getTerm() + "=" + col);
401
pHandler.setParent(parent, col, valueEntry.qName, childParticle, valueEntry.parentParticle);
402
403 /* for (Iterator iter = col.iterator(); iter.hasNext();)
404                               {
405                                  pHandler.setParent(parent, iter.next(), valueEntry.qName, childParticle,
406                                        valueEntry.parentParticle);
407                               }
408 */

409                            }
410                         }
411                         else
412                         {
413                            if(parentValueList != null)
414                            {
415                               parentValueList.addTermValue(valueEntry.qName, childParticle, pHandler, valueEntry.value, valueEntry.parentParticle);
416                            }
417                            else
418                            {
419                               pHandler.setParent(parent, valueEntry.value, valueEntry.qName, childParticle, valueEntry.parentParticle);
420                            }
421                         }
422                      }
423                      else
424                      {
425                         CharactersHandler cHandler = (CharactersHandler)handler;
426                         if(parentValueList != null)
427                         {
428                            parentValueList.addTextValue(valueEntry.qName, childParticle, cHandler, valueEntry.value);
429                         }
430                         else
431                         {
432                            cHandler.setValue(valueEntry.qName, (ElementBinding) childParticle.getTerm(), parent, valueEntry.value);
433                         }
434                      }
435                   }
436                   else if(binding instanceof AttributeBinding)
437                   {
438                      AttributeBinding attr = (AttributeBinding)binding;
439                      AttributeHandler handler = attr.getHandler();
440                      if(handler != null)
441                      {
442                         if(parentValueList != null)
443                         {
444                            parentValueList.setAttributeValue(attr.getQName(), attr, valueEntry.value);
445                         }
446                         else
447                         {
448                            handler.attribute(valueEntry.qName, attr.getQName(), attr, parent, valueEntry.value);
449                         }
450                      }
451                      else
452                      {
453                         throw new JBossXBRuntimeException("Attribute binding present but has no handler: element=" +
454                            valueEntry.qName +
455                            ", attrinute=" +
456                            attr.getQName()
457                         );
458                      }
459                   }
460                   else
461                   {
462                      throw new JBossXBRuntimeException("Unexpected binding type: " + binding);
463                   }
464                }
465
466                return parent;
467             }
468          };
469       }
470       
471       public static ValueListHandler child()
472       {
473          return new ValueListHandler()
474          {
475             public Object JavaDoc newInstance(ParticleBinding particle, ValueList valueList)
476             {
477                if(valueList.size() > 1)
478                {
479                   String JavaDoc msg = "Expected only one child for " + particle.getTerm() + " but got:";
480                   for(int i = 0; i < valueList.size(); ++i)
481                   {
482                      ValueList.NonRequiredValue valueEntry = valueList.getValue(0);
483                      msg += " " + valueEntry.value + ";";
484                   }
485                   throw new JBossXBRuntimeException(msg);
486                }
487                
488                ValueList.NonRequiredValue valueEntry = valueList.getValue(0);
489                return valueEntry.value;
490             }
491          };
492       }
493    };
494       
495    Object JavaDoc newInstance(ParticleBinding particle, ValueList valueList);
496 }
497
Popular Tags