package examples.mega.client;

import java.io.IOException;

import java.net.URL;

import java.util.Iterator;

import java.rmi.RemoteException;

import javax.xml.namespace.QName;

import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.Call;

import javax.xml.soap.SOAPElementFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;

import javax.xml.rpc.encoding.TypeMapping;
import javax.xml.rpc.encoding.TypeMappingRegistry;

import weblogic.webservice.encoding.GenericTypeMapping;
import weblogic.webservice.encoding.DefaultTypeMapping;

public class DynamicClient{

  public static void main( String[] args ) throws Exception{
    new DynamicClient().invoke(
        "http://" + args[0] + ":" + args[1] + 
        "/mega/MegaService?WSDL" );
  }

  public void invoke( String url ) throws RemoteException, 
    InvokeFailedException, ServiceException, IOException, SOAPException{

      generic( url );
      usingAutoType( url );
    }

  public void generic( String url ) throws RemoteException, 
    InvokeFailedException, ServiceException, IOException, SOAPException{

    System.setProperty( "javax.xml.rpc.ServiceFactory",
        "weblogic.webservice.core.rpc.ServiceFactoryImpl" );

    ServiceFactory factory = ServiceFactory.newInstance();

    QName serviceName = new QName( "http://www.bea.com/mega-service/",
        "MegaWebService" );

    Service service = factory.createService( new URL( url ), serviceName );

    TypeMappingRegistry registry = service.getTypeMappingRegistry(); 
    registry.registerDefault( new GenericTypeMapping() ); 

    System.out.println( "+ Service: " + service.getServiceName() );

    QName portName;

    Iterator it = service.getPorts(); 
    if( it.hasNext() ){
      portName = (QName)it.next();
      System.out.println( "  + Port: " + portName );
    }else{
      throw new InvokeFailedException( "No port found" );
    }

    //simple type
    Call call1 = service.createCall( portName, new QName(
          "http://www.bea.com/mega-service/", "helloWorld" ) );

    System.out.println( call1.invoke( null ) );

    //complex type
    Call call2 = service.createCall( portName, new QName(
          "http://www.bea.com/mega-service/", "complexType" ) );

    SOAPElementFactory soapFactory = SOAPElementFactory.newInstance();
    SOAPElement input = soapFactory.create( "data" );
    input.addChildElement( "id" ).addTextNode( "1234" );

    SOAPElement result = (SOAPElement)call2.invoke( new Object[]{input} );
    System.out.println( result );
  }

  public void usingAutoType( String url ) throws RemoteException, 
    InvokeFailedException, ServiceException, IOException, SOAPException{

    System.setProperty( "javax.xml.rpc.ServiceFactory",
        "weblogic.webservice.core.rpc.ServiceFactoryImpl" );

    ServiceFactory factory = ServiceFactory.newInstance();

    QName serviceName = new QName( "http://www.bea.com/mega-service/",
        "MegaWebService" );

    Service service = factory.createService( new URL( url ), serviceName );

    TypeMappingRegistry registry = service.getTypeMappingRegistry(); 

    registry.registerDefault( 
        new DefaultTypeMapping( "temp_dynamic_dir/types.xml" ) ); 

    System.out.println( "+ Service: " + service.getServiceName() );

    QName portName;

    Iterator it = service.getPorts(); 
    if( it.hasNext() ){
      portName = (QName)it.next();
      System.out.println( "  + Port: " + portName );
    }else{
      throw new InvokeFailedException( "No port found" );
    }

    //simple type
    Call call1 = service.createCall( portName, new QName(
          "http://www.bea.com/mega-service/", "helloWorld" ) );

    System.out.println( call1.invoke( null ) );

    //complex type
    Call call2 = service.createCall( portName, new QName(
          "http://www.bea.com/mega-service/", "complexType" ) );

    BaseData input = DataTypes.getBaseData();
    BaseData result = (BaseData)call2.invoke( new Object[]{input} );
    System.out.println( result );
  }

}

