View Javadoc

    1   package org.codehaus.xfire.wsdl11.builder;
    2
    3   import java.io.IOException;
    4   import java.io.OutputStream;
    5   import java.util.HashMap;
    6   import java.util.HashSet;
    7   import java.util.Iterator;
    8   import java.util.Map;
    9   import java.util.Set;
    10
    11  import javax.wsdl.Definition;
    12  import javax.wsdl.WSDLException;
    13  import javax.wsdl.factory.WSDLFactory;
    14
    15  import org.codehaus.xfire.XFireRuntimeException;
    16  import org.codehaus.xfire.service.Service;
    17  import org.codehaus.xfire.soap.SoapConstants;
    18  import org.codehaus.xfire.util.NamespaceHelper;
    19  import org.codehaus.xfire.wsdl.SchemaType;
    20  import org.codehaus.xfire.wsdl.WSDLWriter;
    21  import org.codehaus.yom.Attribute;
    22  import org.codehaus.yom.Document;
    23  import org.codehaus.yom.Element;
    24  import org.codehaus.yom.Elements;
    25  import org.codehaus.yom.Serializer;
    26  import org.codehaus.yom.converters.DOMConverter;
    27
    28  /***
    29   * AbstractWSDL
    30   *
    31   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
    32   */
    33  public abstract class AbstractWSDL
    34      implements WSDLWriter
    35  {
    36      private Definition def;
    37
    38      private String targetNamespace;
    39
    40      private Service service;
    41
    42      private Document wsdlDocument;
    43
    44      private Map dependencies = new HashMap();
    45
    46      private Map namespaceImports = new HashMap();
    47
    48      private Element schemaTypes;
    49
    50      private Map typeMap;
    51
    52      private WSDLBuilderInfo info;
    53
    54      /*-------------------------------------------------
    55       * Namespace and QName definitions for easy access.
    56       *-------------------------------------------------*/
    57
    58      public final static String schemaQ = SoapConstants.XSD_PREFIX + ":" + "schema";
    59
    60      public final static String elementQ = SoapConstants.XSD_PREFIX + ":" + "element";
    61
    62      public final static String complexQ = SoapConstants.XSD_PREFIX + ":" + "complexType";
    63
    64      public final static String sequenceQ = SoapConstants.XSD_PREFIX + ":" + "sequence";
    65
    66      public AbstractWSDL(Service service) throws WSDLException
    67      {
    68          this.service = service;
    69          this.info = (WSDLBuilderInfo) service.getProperty(WSDLBuilderInfo.KEY);
    70
    71          if (info == null)
    72              info = new WSDLBuilderInfo(service);
    73
    74          setDefinition(WSDLFactory.newInstance().newDefinition());
    75          getDefinition().setTargetNamespace(info.getTargetNamespace());
    76
    77          Element root = new Element("wsdl:types", WSDL11_NS);
    78          setSchemaTypes(root);
    79          root.addNamespaceDeclaration(SoapConstants.XSD_PREFIX, SoapConstants.XSD);
    80
    81          addNamespace("soap", service.getSoapVersion().getNamespace());
    82          addNamespace("soapenc", service.getSoapVersion().getSoapEncodingStyle());
    83          addNamespace("xsd", SoapConstants.XSD);
    84          addNamespace("wsdl", WSDL11_NS);
    85          addNamespace("wsdlsoap", WSDL11_SOAP_NS);
    86          addNamespace("tns", info.getTargetNamespace());
    87
    88          typeMap = new HashMap();
    89      }
    90
    91      protected void writeDocument()
    92          throws WSDLException
    93      {
    94          writeImports();
    95
    96          org.w3c.dom.Document doc = WSDLFactory.newInstance().newWSDLWriter().getDocument(def);
    97
    98          wsdlDocument = DOMConverter.convert(doc);
    99
    100         writeComplexTypes();
    101     }
    102
    103     /***
    104      * Write xs:import elements for each schema.
    105      */
    106     protected void writeImports()
    107     {
    108         for (Iterator itr = namespaceImports.entrySet().iterator(); itr.hasNext();)
    109         {
    110             Map.Entry entry = (Map.Entry) itr.next();
    111
    112             String uri = (String) entry.getKey();
    113             Set imports = (Set) entry.getValue();
    114
    115             Element schema = createSchemaType(uri);
    116
    117             for (Iterator importItr = imports.iterator(); importItr.hasNext();)
    118             {
    119                 String ns = (String) importItr.next();
    120                 if (!ns.equals(SoapConstants.XSD) && !hasImport(schema, ns))
    121                 {
    122                     Element importEl = new Element("xsd:import", SoapConstants.XSD);
    123                     importEl.addAttribute(new Attribute("namespace", ns));
    124
    125                     schema.insertChild(importEl, 0);
    126                 }
    127             }
    128         }
    129     }
    130
    131     public boolean hasImport(Element schema, String ns)
    132     {
    133         Elements children = schema.getChildElements("import", SoapConstants.XSD);
    134
    135         for (int i = 0; i < children.size(); i++)
    136         {
    137             Element importEl = children.get(i);
    138             String value = importEl.getAttributeValue("namespace");
    139
    140             if (value != null && value.equals(ns)) return true;
    141         }
    142
    143         return false;
    144     }
    145
    146     protected void writeComplexTypes()
    147         throws WSDLException
    148     {
    149         Element rootEl = getDocument().getRootElement();
    150
    151         if (schemaTypes.getChildCount() > 0)
    152         {
    153             schemaTypes.detach();
    154             rootEl.insertChild(schemaTypes, 0);
    155         }
    156
    157     }
    158
    159     public void addDependency(SchemaType type)
    160     {
    161         if (!type.isComplex())
    162         {
    163             return;
    164         }
    165
    166         if (!hasDependency(type))
    167         {
    168             dependencies.put(type.getSchemaType(), type);
    169
    170             Element e = createSchemaType(type.getSchemaType().getNamespaceURI());
    171             type.writeSchema(e);
    172
    173             Set deps = type.getDependencies();
    174
    175             if (deps != null)
    176             {
    177                 for (Iterator itr = deps.iterator(); itr.hasNext();)
    178                 {
    179                     SchemaType child = (SchemaType) itr.next();
    180                     addDependency(child);
    181                     addNamespaceImport(type.getSchemaType().getNamespaceURI(),
    182                                        child.getSchemaType().getNamespaceURI());
    183                 }
    184             }
    185         }
    186     }
    187
    188     protected boolean hasDependency(SchemaType type)
    189     {
    190         return dependencies.containsKey(type.getSchemaType());
    191     }
    192
    193     /***
    194      * Adds an import to another namespace.
    195      * @param uri The namespace to import into.
    196      * @param imported The namespace to import.
    197      */
    198     public void addNamespaceImport(String uri, String imported)
    199     {
    200         if (uri.equals(imported)) return;
    201
    202         Set imports = (Set) namespaceImports.get(uri);
    203
    204         if (imports == null)
    205         {
    206             imports = new HashSet();
    207             namespaceImports.put(uri, imports);
    208         }
    209
    210         imports.add(imported);
    211     }
    212
    213     /***
    214      * @see org.codehaus.xfire.wsdl.WSDLWriter#write(java.io.OutputStream)
    215      */
    216     public void write(OutputStream out)
    217         throws IOException
    218     {
    219         Serializer writer = new Serializer(out);
    220         writer.write(getDocument());
    221         writer.flush();
    222     }
    223
    224     public void addNamespace(String prefix, String uri)
    225     {
    226         def.addNamespace(prefix, uri);
    227
    228         String declaredUri = schemaTypes.getNamespaceURI(prefix);
    229         if (declaredUri == null)
    230         {
    231             schemaTypes.addNamespaceDeclaration(prefix, uri);
    232         }
    233         else if (!declaredUri.equals(uri))
    234         {
    235             throw new XFireRuntimeException("Namespace conflict: " + declaredUri
    236                     + " was declared but " + uri + " was attempted.");
    237         }
    238     }
    239
    240     public String getNamespacePrefix(String uri)
    241     {
    242         return NamespaceHelper.getUniquePrefix(schemaTypes, uri);
    243     }
    244
    245     public WSDLBuilderInfo getInfo()
    246     {
    247         return info;
    248     }
    249
    250     /***
    251      * @see org.codehaus.xfire.wsdl.WSDLWriter#getDocument()
    252      */
    253     public Document getDocument()
    254     {
    255         return wsdlDocument;
    256     }
    257
    258     public Definition getDefinition()
    259     {
    260         return def;
    261     }
    262
    263     public void setDefinition(Definition definition)
    264     {
    265         this.def = definition;
    266     }
    267
    268     public Service getService()
    269     {
    270         return service;
    271     }
    272
    273     public void setService(Service service)
    274     {
    275         this.service = service;
    276     }
    277
    278     /***
    279      * Create a shcema type element and store it to be written later on.
    280      *
    281      * @param namespace
    282      *            The namespace to create the type in.
    283      * @return
    284      */
    285     public Element createSchemaType(String namespace)
    286     {
    287         Element e = (Element) typeMap.get(namespace);
    288
    289         if (e == null)
    290         {
    291             e = new Element(schemaQ, SoapConstants.XSD);
    292
    293             e.addAttribute(new Attribute("targetNamespace", namespace));
    294             e.addAttribute(new Attribute("elementFormDefault", "qualified"));
    295             e.addAttribute(new Attribute("attributeFormDefault", "qualified"));
    296
    297             setSchema(namespace, e);
    298         }
    299
    300         return e;
    301     }
    302
    303     protected boolean hasSchema(String namespace)
    304     {
    305         return typeMap.containsKey(namespace);
    306     }
    307
    308     protected void setSchema(String namespace, Element schema)
    309     {
    310         typeMap.put(namespace, schema);
    311         getSchemaTypes().appendChild(schema);
    312     }
    313
    314     protected Element getSchemaTypes()
    315     {
    316         return schemaTypes;
    317     }
    318
    319     protected void setSchemaTypes(Element schemaTypes)
    320     {
    321         this.schemaTypes = schemaTypes;
    322     }
    323 }