/**
   * This method creates a WSDL document containing the partner link types.
   *
   * @param model The global protocol model
   * @param role The role of the process
   * @param localcm The local protocol model
   * @param bpelProcess The BPEL process
   * @param journal The feedback handler
   * @return The WSDL document containing the partner link types
   * @throws Exception Failed to generate the partner link types
   */
  public static org.w3c.dom.Document generatePartnerLinkTypes(
      ProtocolModel model,
      Role role,
      ProtocolModel localcm,
      TProcess bpelProcess,
      FeedbackHandler journal)
      throws Exception {
    org.w3c.dom.Document doc =
        javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    org.w3c.dom.Element defn = doc.createElement(WSDL_DEFINITIONS);
    doc.appendChild(defn);

    defn.setAttribute(XMLNS_PLNK, PLNKTYPE_NS);
    defn.setAttribute(XMLNS_WSDL, WSDL_NS);

    defn.setAttribute(NAME_LABEL, localcm.getProtocol().getName());

    defn.setAttribute(TARGET_NAMESPACE_LABEL, bpelProcess.getTargetNamespace());

    ContractGenerator cg = ContractGeneratorFactory.getContractGenerator();

    // Add import to associated wsdl
    String wsdlName = WSDLGeneratorUtil.getWSDLFileName(role, localcm.getProtocol().getName(), "");

    org.w3c.dom.Element imp = doc.createElement(WSDL_IMPORT);

    imp.setAttribute("namespace", bpelProcess.getTargetNamespace());
    imp.setAttribute("location", wsdlName);

    defn.appendChild(imp);

    // Add imports for associated roles
    java.util.ListIterator<Role> roles = localcm.getProtocol().getRoles().listIterator();

    while (roles.hasNext()) {
      Role r = roles.next();

      // Check if role is a client parameter - if so,
      // don't include an import for it
      if (localcm.getProtocol().getParameterDefinition(r.getName()) != null) {
        continue;
      }

      Contract contract = null;

      if (cg != null) {
        contract = cg.generate(model.getProtocol(), null, r, journal);
      }

      if (contract != null) {
        boolean gen = false;

        java.util.Iterator<Interface> iter = contract.getInterfaces().iterator();

        while (gen == false && iter.hasNext()) {
          Interface intf = iter.next();

          if (intf.getMessageExchangePatterns().size() > 0) {
            gen = true;
          }
        }

        if (gen) {
          wsdlName = WSDLGeneratorUtil.getWSDLFileName(r, localcm.getProtocol().getName(), "");

          imp = doc.createElement(WSDL_IMPORT);

          imp.setAttribute("namespace", contract.getNamespace());
          imp.setAttribute("location", wsdlName);

          defn.appendChild(imp);
        }
      }
    }

    // Create partner link types
    java.util.Map<String, String> nsMap = new java.util.HashMap<String, String>();

    for (TPartnerLink pl : bpelProcess.getPartnerLinks().getPartnerLink()) {
      org.w3c.dom.Element plt = doc.createElement(PLNK_PARTNER_LINK_TYPE);

      plt.setAttribute(NAME_LABEL, pl.getPartnerLinkType().getLocalPart());

      if (pl.getPartnerRole() != null && pl.getPartnerRole().trim().length() > 0) {
        org.w3c.dom.Element plRole = doc.createElement(PLNK_ROLE);

        plt.appendChild(plRole);

        plRole.setAttribute(NAME_LABEL, pl.getPartnerRole());

        Role useRole = null;

        for (int i = 0; useRole == null && i < localcm.getProtocol().getRoles().size(); i++) {
          if (pl.getPartnerRole().startsWith(localcm.getProtocol().getRoles().get(i).getName())) {
            useRole = localcm.getProtocol().getRoles().get(i);
          }
        }

        Contract contract = null;

        if (cg != null && useRole != null) {
          contract = cg.generate(model.getProtocol(), null, useRole, journal);
        }

        if (contract != null) {
          Interface intf = null;

          if (pl.getMyRole() != null) {
            intf = contract.getInterface(pl.getMyRole());
          }

          if (intf == null && contract.getInterfaces().size() > 0) {
            intf = contract.getInterfaces().iterator().next();
          }

          if (intf != null) {
            String prefix = null;
            String portType = intf.getName();

            if (intf.getNamespace() != null) {
              prefix = XMLUtils.getPrefixForNamespace(intf.getNamespace(), nsMap);

              portType = prefix + ":" + portType;
            }

            plRole.setAttribute(PORT_TYPE_LABEL, portType);
          }
        }
      }

      if (pl.getMyRole() != null && pl.getMyRole().trim().length() > 0) {
        org.w3c.dom.Element plRole = doc.createElement(PLNK_ROLE);

        plt.appendChild(plRole);

        plRole.setAttribute(NAME_LABEL, pl.getMyRole());

        Contract contract = null;

        if (cg != null) {
          String linkName = pl.getPartnerLinkType().getLocalPart();

          int pos = linkName.indexOf("To");

          if (pos != -1) {
            java.util.Set<Role> clientRoles = new java.util.HashSet<Role>();

            clientRoles.add(new Role(linkName.substring(0, pos)));

            contract = cg.generate(model.getProtocol(), clientRoles, role, journal);
          } else {
            contract = cg.generate(model.getProtocol(), null, role, journal);
          }
        }

        if (contract != null) {
          Interface intf = null;

          if (pl.getMyRole() != null) {
            intf = contract.getInterface(pl.getMyRole());
          }

          if (intf == null && contract.getInterfaces().size() > 0) {
            intf = contract.getInterfaces().iterator().next();
          }

          if (intf != null) {
            String prefix = null;
            String portType = intf.getName();

            if (intf.getNamespace() != null) {
              prefix = XMLUtils.getPrefixForNamespace(intf.getNamespace(), nsMap);

              portType = prefix + ":" + portType;
            }

            plRole.setAttribute(PORT_TYPE_LABEL, portType);
          }
        }
      }

      defn.appendChild(plt);
    }

    // Create remaining namespace/prefix mappings
    java.util.Iterator<String> iter = nsMap.keySet().iterator();
    while (iter.hasNext()) {
      String ns = iter.next();
      String prefix = nsMap.get(ns);

      defn.setAttribute(XMLNS_PREFIX + prefix, ns);
    }

    return (doc);
  }
  protected static void initializeService(
      org.w3c.dom.Element service,
      TProcess bpelProcess,
      TPartnerLink pl,
      java.util.Collection<javax.wsdl.Definition> wsdls,
      org.w3c.dom.Element partnerLinkTypes,
      java.util.Map<String, String> nsMap) {
    QName serviceName = null;
    String servicePort = null;

    // Get partner link type details
    QName partnerLinkType = pl.getPartnerLinkType();

    org.w3c.dom.NodeList nl = partnerLinkTypes.getChildNodes();

    String portType = null;

    for (int i = 0; portType == null && i < nl.getLength(); i++) {
      org.w3c.dom.Node n = nl.item(i);

      if (n instanceof org.w3c.dom.Element
          && XMLUtils.getLocalname(n.getNodeName()).equals(PARTNER_LINK_TYPE)) {
        org.w3c.dom.Element plt = (org.w3c.dom.Element) nl.item(i);

        String name = plt.getAttribute("name");

        if (name != null && name.equals(partnerLinkType.getLocalPart())) {
          org.w3c.dom.NodeList nl2 = plt.getChildNodes();

          for (int j = 0; portType == null && j < nl2.getLength(); j++) {
            org.w3c.dom.Node n2 = nl2.item(j);

            if (n2 instanceof org.w3c.dom.Element
                && XMLUtils.getLocalname(n2.getNodeName()).equals("role")) {
              org.w3c.dom.Element role = (org.w3c.dom.Element) n2;
              String roleName = role.getAttribute("name");

              if ((pl.getMyRole() != null && pl.getMyRole().equals(roleName))
                  || (pl.getPartnerRole() != null && pl.getPartnerRole().equals(roleName))) {
                portType = role.getAttribute("portType");

                String ptprefix = XMLUtils.getPrefix(portType);

                String ptns = partnerLinkTypes.getAttribute("xmlns:" + ptprefix);

                String newprefix = XMLUtils.getPrefixForNamespace(ptns, nsMap);

                portType = newprefix + ":" + XMLUtils.getLocalname(portType);
              }
            }
          }
        }
      }
    }

    if (portType != null) {
      String portTypePrefix = XMLUtils.getPrefix(portType);
      String portTypeNS = XMLUtils.getNamespaceForPrefix(portTypePrefix, nsMap);
      QName ptQName = new QName(portTypeNS, XMLUtils.getLocalname(portType));

      for (javax.wsdl.Definition wsdl : wsdls) {
        if (wsdl.getTargetNamespace().equals(portTypeNS)) {

          @SuppressWarnings("unchecked")
          java.util.Collection<javax.wsdl.Service> services = wsdl.getServices().values();

          for (javax.wsdl.Service s : services) {

            @SuppressWarnings("unchecked")
            java.util.Collection<javax.wsdl.Port> ports = s.getPorts().values();

            for (javax.wsdl.Port p : ports) {

              if (p.getBinding() != null
                  && p.getBinding().getPortType() != null
                  && p.getBinding().getPortType().getQName().equals(ptQName)) {
                serviceName = s.getQName();
                servicePort = p.getName();
              }
            }
          }
        }
      }

      if (serviceName != null) {
        String prefix = XMLUtils.getPrefixForNamespace(serviceName.getNamespaceURI(), nsMap);

        service.setAttribute("name", prefix + ":" + serviceName.getLocalPart());
      }

      if (servicePort != null) {
        service.setAttribute("port", servicePort);
      }
    }
  }