View Javadoc

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