View Javadoc

    1   package org.codehaus.xfire.aegis.type.collection;
    2
    3
    4   import java.util.HashMap;
    5   import java.util.Iterator;
    6   import java.util.Map;
    7
    8   import javax.xml.namespace.QName;
    9
    10  import org.codehaus.xfire.MessageContext;
    11  import org.codehaus.xfire.XFireRuntimeException;
    12  import org.codehaus.xfire.aegis.MessageReader;
    13  import org.codehaus.xfire.aegis.MessageWriter;
    14  import org.codehaus.xfire.aegis.type.Type;
    15  import org.codehaus.xfire.fault.XFireFault;
    16  import org.codehaus.xfire.soap.SoapConstants;
    17  import org.codehaus.xfire.util.NamespaceHelper;
    18  import org.codehaus.yom.Attribute;
    19  import org.codehaus.yom.Element;
    20
    21  public class MapType
    22      extends Type
    23  {
    24      private Class keyClass;
    25      private Class valueClass;
    26      private QName keyName;
    27      private QName valueName;
    28      private QName entryName;
    29
    30      public MapType(QName schemaType, Class keyClass, Class valueClass)
    31      {
    32          super();
    33
    34          this.keyClass = keyClass;
    35          this.valueClass = valueClass;
    36
    37          setSchemaType(schemaType);
    38          setKeyName(new QName(schemaType.getNamespaceURI(), "key"));
    39          setValueName(new QName(schemaType.getNamespaceURI(), "value"));
    40          setEntryName(new QName(schemaType.getNamespaceURI(), "entry"));
    41      }
    42
    43      public Object readObject(MessageReader reader, MessageContext context)
    44          throws XFireFault
    45      {
    46          Map map = instantiateMap();
    47          try
    48          {
    49              Type keyType = getKeyType();
    50              Type valueType = getValueType();
    51
    52              Object key = null;
    53              Object value = null;
    54
    55              while (reader.hasMoreElementReaders())
    56              {
    57                  MessageReader entryReader = reader.getNextElementReader();
    58
    59                  if (entryReader.getName().equals(getEntryName()))
    60                  {
    61                      while (entryReader.hasMoreElementReaders())
    62                      {
    63                          MessageReader evReader = entryReader.getNextElementReader();
    64
    65                          if (evReader.getName().equals(getKeyName()))
    66                          {
    67                              key = keyType.readObject(evReader, context);
    68                          }
    69                          else if (evReader.getName().equals(getValueName()))
    70                          {
    71                              value = valueType.readObject(evReader, context);
    72                          }
    73                          else
    74                          {
    75                              readToEnd(evReader);
    76                          }
    77                      }
    78
    79                      map.put(key, value);
    80                  }
    81                  else
    82                  {
    83                      readToEnd(entryReader);
    84                  }
    85              }
    86
    87              return map;
    88          }
    89          catch (IllegalArgumentException e)
    90          {
    91              throw new XFireRuntimeException("Illegal argument.", e);
    92          }
    93      }
    94
    95      private void readToEnd(MessageReader childReader)
    96      {
    97          while (childReader.hasMoreElementReaders())
    98          {
    99              readToEnd(childReader.getNextElementReader());
    100         }
    101     }
    102
    103     /***
    104      * Creates a map instance. If the type class is a <code>Map</code> or extends
    105      * the <code>Map</code> interface a <code>HashMap</code> is created. Otherwise
    106      * the map classs (i.e. LinkedHashMap) is instantiated using the default constructor.
    107      *
    108      * @return
    109      */
    110     protected Map instantiateMap()
    111     {
    112         Map map = null;
    113
    114         if (getTypeClass().equals(Map.class) || getTypeClass().isInterface())
    115         {
    116             map = new HashMap();
    117         }
    118         else
    119         {
    120             try
    121             {
    122                 map = (Map) getTypeClass().newInstance();
    123             }
    124             catch (Exception e)
    125             {
    126                 throw new XFireRuntimeException(
    127                     "Could not create map implementation: " + getTypeClass().getName(), e);
    128             }
    129         }
    130
    131         return map;
    132     }
    133
    134     public void writeObject(Object object, MessageWriter writer, MessageContext context)
    135         throws XFireFault
    136     {
    137         if (object == null)
    138             return;
    139
    140         try
    141         {
    142             Map map = (Map) object;
    143
    144             Type keyType = getKeyType();
    145             Type valueType = getValueType();
    146
    147             if (keyType == null)
    148                 throw new XFireRuntimeException("Couldn't find type for key class "
    149                                                 + keyType.getTypeClass() + ".");
    150
    151             if (valueType == null)
    152                 throw new XFireRuntimeException("Couldn't find type for value class "
    153                                                 + keyType.getTypeClass() + ".");
    154
    155
    156             for (Iterator itr = map.entrySet().iterator(); itr.hasNext();)
    157             {
    158                 Map.Entry entry = (Map.Entry) itr.next();
    159
    160                 MessageWriter entryWriter = writer.getElementWriter(getEntryName());
    161
    162                 MessageWriter keyWriter = entryWriter.getElementWriter(getKeyName());
    163                 keyType.writeObject(entry.getKey(), keyWriter, context);
    164                 keyWriter.close();
    165
    166                 MessageWriter valueWriter = entryWriter.getElementWriter(getValueName());
    167                 valueType.writeObject(entry.getValue(), valueWriter, context);
    168                 valueWriter.close();
    169
    170                 entryWriter.close();
    171             }
    172         }
    173         catch (IllegalArgumentException e)
    174         {
    175             throw new XFireRuntimeException("Illegal argument.", e);
    176         }
    177     }
    178
    179     public void writeSchema(Element root)
    180     {
    181         String ctPref = SoapConstants.XSD_PREFIX + ":complexType";
    182         String seqPref = SoapConstants.XSD_PREFIX + ":sequence";
    183
    184         Element complex = new Element(ctPref, SoapConstants.XSD);
    185         complex.addAttribute(new Attribute("name", getSchemaType().getLocalPart()));
    186         root.appendChild(complex);
    187
    188         Element seq = new Element(seqPref, SoapConstants.XSD);
    189         complex.appendChild(seq);
    190
    191         Type keyType = getKeyType();
    192         Type valueType = getValueType();
    193
    194         String prefix = NamespaceHelper.getUniquePrefix((Element) root.getParent(),
    195                                                         getSchemaType().getNamespaceURI());
    196
    197         String keyTypeName = prefix + ":" + keyType.getSchemaType().getLocalPart();
    198         String valueTypeName = prefix + ":" + valueType.getSchemaType().getLocalPart();
    199
    200         Element element = new Element(SoapConstants.XSD_PREFIX + ":element", SoapConstants.XSD);
    201         seq.appendChild(element);
    202
    203         element.addAttribute(new Attribute("name", getEntryName().getLocalPart()));
    204         element.addAttribute(new Attribute("minOccurs", "0"));
    205         element.addAttribute(new Attribute("maxOccurs", "unbounded"));
    206
    207         Element evComplex = new Element(ctPref, SoapConstants.XSD);
    208         element.appendChild(evComplex);
    209
    210         Element evseq = new Element(seqPref, SoapConstants.XSD);
    211         evComplex.appendChild(evseq);
    212
    213         createElement(evseq, getKeyName(), keyTypeName);
    214         createElement(evseq, getValueName(), valueTypeName);
    215     }
    216
    217     private void createElement(Element seq, QName name, String keyTypeName)
    218     {
    219         Element element = new Element(SoapConstants.XSD_PREFIX + ":element", SoapConstants.XSD);
    220         seq.appendChild(element);
    221
    222         element.addAttribute(new Attribute("name", name.getLocalPart()));
    223         element.addAttribute(new Attribute("type", keyTypeName));
    224
    225         element.addAttribute(new Attribute("minOccurs", "0"));
    226         element.addAttribute(new Attribute("maxOccurs", "1"));
    227     }
    228
    229     public Type getKeyType()
    230     {
    231         return getOrCreateType(keyClass);
    232     }
    233
    234     private Type getOrCreateType(Class clazz)
    235     {
    236         Type type = getTypeMapping().getType(clazz);
    237         if (type == null)
    238         {
    239             System.out.println("Couldn't find type for " + clazz);
    240             type = getTypeMapping().getTypeCreator().createType(clazz);
    241             getTypeMapping().register(type);
    242         }
    243         return type;
    244     }
    245
    246     public Type getValueType()
    247     {
    248         return getOrCreateType(valueClass);
    249     }
    250
    251     public Class getKeyClass()
    252     {
    253         return keyClass;
    254     }
    255
    256     public void setKeyClass(Class keyClass)
    257     {
    258         this.keyClass = keyClass;
    259     }
    260
    261     public QName getKeyName()
    262     {
    263         return keyName;
    264     }
    265
    266     public void setKeyName(QName keyName)
    267     {
    268         this.keyName = keyName;
    269     }
    270
    271     public Class getValueClass()
    272     {
    273         return valueClass;
    274     }
    275
    276     public void setValueClass(Class valueClass)
    277     {
    278         this.valueClass = valueClass;
    279     }
    280
    281     public QName getValueName()
    282     {
    283         return valueName;
    284     }
    285
    286     public void setValueName(QName valueName)
    287     {
    288         this.valueName = valueName;
    289     }
    290
    291     public QName getEntryName()
    292     {
    293         return entryName;
    294     }
    295
    296     public void setEntryName(QName entryName)
    297     {
    298         this.entryName = entryName;
    299     }
    300 }