/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

// $Id: WSDDGenerator.java,v 1.22.2.10 2005/07/04 17:14:46 tdiesler Exp $
package org.jboss.webservice.deployment;

// $Id: WSDDGenerator.java,v 1.22.2.10 2005/07/04 17:14:46 tdiesler Exp $

import org.jboss.axis.Constants;
import org.jboss.axis.enums.Style;
import org.jboss.axis.enums.Use;
import org.jboss.logging.Logger;
import org.jboss.xb.binding.NamespaceRegistry;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedHashMap;

/**
 * Generate the Axis deployment wsdd
 * <p/>
 * Although there is a <code>wsdlFile</code> element in the wsdd it not used by axis to describe the service
 * the only purpose is, to return that file upon the ?WSDL operation
 *
 * @author Thomas.Diesler@jboss.org
 * @since 08-Jun-2004
 */
public class WSDDGenerator
{
   // provide logging
   private final Logger log = Logger.getLogger(WSDDGenerator.class);

   // The generated service description
   private ServiceDescription serviceDesc;

   /**
    * A wsdd generator for a preconfigured ServiceDescription
    */
   public WSDDGenerator(ServiceDescription service)
   {
      this.serviceDesc = service;
   }

   /**
    * Generate the entire WSDD file
    */
   public void generateDeployment(PrintWriter out, String serviceName, String provider)
   {
      appendHeader(out);
      appendServiceElement(out, serviceName, provider);
      appendOperations(out);
      appendTypeMappings(out);
      appendFooter(out);
      out.close();
   }

   public void appendHeader(PrintWriter out)
   {
      out.println("<deployment");
      out.println(" xmlns='http://xml.apache.org/axis/wsdd/'");
      out.println(" xmlns:java='http://xml.apache.org/axis/wsdd/providers/java'");
      out.println(" xmlns:soap='" + Constants.URI_SOAP11_ENC + "'");
      out.println(" xmlns:" + Constants.NS_PREFIX_SCHEMA_XSI + "='" + Constants.URI_DEFAULT_SCHEMA_XSI + "'");
      out.println(" xmlns:" + Constants.NS_PREFIX_SCHEMA_XSD + "='" + Constants.URI_DEFAULT_SCHEMA_XSD + "'>");
      out.println();
   }


   /** Append the service element
    */
   public void appendServiceElement(PrintWriter out, String serviceID, String provider)
   {
      Style style = serviceDesc.getStyle();
      String styleStr = (style != null ? "style='" + style + "' " : " ");

      Use use = serviceDesc.getUse();
      String useStr = (use != null ? "use='" + use + "' " : " ");

      out.println("<service name='" + serviceID + "' " + styleStr + useStr + "provider='" + provider + "'>");
      out.println();
   }

   /** Append the operation information, which is taken from the wsdl
    */
   public void appendOperations(PrintWriter out)
   {
      String[] opNames = serviceDesc.getOperationNames();
      Arrays.sort(opNames);

      for (int i = 0; i < opNames.length; i++)
      {
         String opName = opNames[i];
         OperationDescription operation = serviceDesc.getOperation(opName);
         operation.writeWSDD(out);
      }
      out.println();
   }

   /** Append the typeMapping information, which is taken from the wsdl and jaxrpc-mapping.xml
    */
   public void appendTypeMappings(PrintWriter out)
   {
      QName[] typeQNames = serviceDesc.getTypMappingNames();

      // Sort the QNames independent of QName implements Compareable
      // The jdk1.5 version of QName does not implement Compareable
      LinkedHashMap typeQNameMap = new LinkedHashMap();
      for (int i = 0; i < typeQNames.length; i++)
         typeQNameMap.put(typeQNames[i].toString(), typeQNames[i]);

      String[] typeNames = new String[typeQNames.length];
      typeQNameMap.keySet().toArray(typeNames);
      Arrays.sort(typeNames);

      for (int i = 0; i < typeNames.length; i++)
      {
         QName typeQName = (QName)typeQNameMap.get(typeNames[i]);
         TypeMappingDescription typeMapping = serviceDesc.getTypeMapping(typeQName);
         typeMapping.writeWSDD(out);
         out.println();
      }
      out.println();
   }

   public void appendFooter(PrintWriter out)
   {
      out.println("</service>");
      out.println("</deployment>");
   }

   public static String getQNameAttrValue(QName qname)
   {
      if (qname == null)
         throw new IllegalArgumentException("Cannot convert null qname");

      String qnamePrefix = qname.getPrefix();
      if (qnamePrefix.length() > 0)
         qnamePrefix += ":";

      String qnameAttr = qnamePrefix + qname.getLocalPart();
      return qnameAttr;
   }

   /**
    * WSDDGenerator [wsdl] [jaxrpc-mapping] [portName]
    */
   public static void main(String[] args) throws Exception
   {

      URL wsdlURL = null;
      URL jaxrpcURL = null;
      String portName = null;

      if (args.length > 0)
      {
         try
         {
            wsdlURL = new URL(args[0]);
         }
         catch (MalformedURLException e)
         {
            wsdlURL = new File(args[0]).toURL();
         }
      }

      if (args.length > 1)
      {
         try
         {
            jaxrpcURL = new URL(args[1]);
         }
         catch (MalformedURLException e)
         {
            jaxrpcURL = new File(args[1]).toURL();
         }
      }

      if (args.length > 2)
         portName = args[2];

      ServiceDescription serviceDesc = new ServiceDescription(wsdlURL, jaxrpcURL, portName);
      serviceDesc.dumpWsdlDefinition(System.out);

      System.out.println("-------------------------------------------------------------------");

      WSDDGenerator generator = new WSDDGenerator(serviceDesc);

      StringWriter buffer = new StringWriter(1024);
      PrintWriter out = new PrintWriter(buffer);

      String serviceName = serviceDesc.getWsdlService().getQName().getLocalPart();
      generator.generateDeployment(out, serviceName, "Handler");

      System.out.println(buffer.toString());

      // sanity check if we can parse it
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setNamespaceAware(true);
      factory.setValidating(false);
      DocumentBuilder builder = factory.newDocumentBuilder();
      builder.parse(new ByteArrayInputStream(buffer.toString().getBytes()));

      File file = new File("ws4ee-deployment.xml");
      out = new PrintWriter(new FileWriter(file));
      out.println(buffer.toString());
      out.close();

      System.out.println(file.getCanonicalPath());
   }
}
