/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "SOAP" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2000, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package samples.addressbook;

import java.io.*;
import java.util.*;
import java.net.*;
import org.w3c.dom.*;
import org.apache.soap.util.xml.*;
import org.apache.soap.*;
import org.apache.soap.encoding.*;
import org.apache.soap.encoding.soapenc.*;
import org.apache.soap.rpc.*;

/**
 * See \samples\addressbook\readme for info.
 * Runs GetAddress / PutAddress in cycle in concurrent calls
 * from different threads
 *
 * @author Pavel Ausianik (pavel_ausianik@epam.com)
 */

public class ComplexRequest implements Runnable {

    // Maximum Requests
    public static int maxIterations = 100;
    // Number of supported calls
    public static final int NUM_CALLS = 4;
    public static final int PUT_ADDRESS_0 = 0;
    public static final int GET_ADDRESS_0 = 1;
    public static final int PUT_ADDRESS_1 = 2;
    public static final int GET_ADDRESS_1 = 3;


    // Current request
    public static int currentRequest;
    // Number of running threads
    public static int numberRequests;

    static SOAPMappingRegistry smr = new SOAPMappingRegistry();

    static String encodingStyleURI;
    static URL url;


    Call call;

    ComplexRequest() {
        call = new Call();

        call.setSOAPMappingRegistry(smr);
        call.setTargetObjectURI("urn:AddressFetcher");
        call.setEncodingStyleURI(encodingStyleURI);
    }

    /**
     * Make a Call to an RPC service with desired reqest type
     */
    public void makeCall (int requestType)
            throws SOAPException {
        // Prepare call params
        Vector params = new Vector();
        switch (requestType) {
            case PUT_ADDRESS_0:
                String nameToRegister = "NAME_0 NAME_0";
                Address address = new Address(0, "Street_0", "City_0", "State_0",
                        0, new PhoneNumber(0, "000000", "000000"));
                call.setMethodName("addEntry");

                params.addElement(new Parameter("nameToRegister", String.class,
                                                nameToRegister, null));
                params.addElement(new Parameter("address", Address.class,
                                                address, null));
                call.setParams(params);
                break;

            case PUT_ADDRESS_1:
                nameToRegister = "NAME_1 NAME_1";
                address = new Address(1, "Street_1", "City_1", "State_1",
                        0, new PhoneNumber(01, "111111", "111111"));
                call.setMethodName("addEntry");

                params.addElement(new Parameter("nameToRegister", String.class,
                                                nameToRegister, null));
                params.addElement(new Parameter("address", Address.class,
                                                address, null));
                break;
            case GET_ADDRESS_0:
                String nameToLookup = "NAME_0 NAME_0";
                call.setMethodName("getAddressFromName");

                params.addElement(new Parameter("nameToLookup", String.class,
                                                nameToLookup, null));

                break;
            case GET_ADDRESS_1:
                nameToLookup = "NAME_1 NAME_1";
                call.setMethodName("getAddressFromName");

                params.addElement(new Parameter("nameToLookup", String.class,
                                                nameToLookup, null));

                break;
        }

        call.setParams(params);

        // Invoke the call.
        Response resp = call.invoke(url, "");


        // Check the response.
        if (!resp.generatedFault())
        {
//          System.out.println("Request " + requestType + " has been finished. Thread:" + Thread.currentThread().getName());
        }
        else
        {
          Fault fault = resp.getFault();

          System.err.println("Generated fault: " + fault);
        }
    }

    /**
     * run method of the runnable interface
     * run Thread, until desired number of calls done
     */
    public void run() {
        synchronized (ComplexRequest.class) {
            numberRequests++;
        }
        while (true) {
            try {
                // Get new request type, until available
                int requestType = getNextRequestType();
                if (requestType == -1)
                    break;
                makeCall(requestType);

            }
            catch (SOAPException se)
            {
                // Print and continue running
                se.printStackTrace();
            }
            catch (Throwable e) {
                // Print and stop
                e.printStackTrace();
                break;
            }
        }
        synchronized (ComplexRequest.class) {
            numberRequests--;
        }
    }

    /**
     * returns next request type, shifting it in turn 0-1-2-3
     */
    public synchronized int getNextRequestType() {
        if (currentRequest < maxIterations) {
            return (currentRequest ++) % NUM_CALLS;
        }
        return -1;
    }

    public static void main(String[] args) throws Exception
    {
      if (args.length != 3
          && (args.length != 4 || !args[0].startsWith("-")))
      {
        System.err.println("Usage:");
        System.err.println("  java " + ComplexRequest.class.getName() +
                           " [-encodingStyleURI] SOAP-router-URL NumberOfCalls NumberofThreads");
        System.exit (1);
      }

      // Process the arguments.
      int offset = 4 - args.length;
      encodingStyleURI = args.length == 4
                                ? args[0].substring(1)
                                : Constants.NS_URI_SOAP_ENC;
      url = new URL(args[1 - offset]);
      maxIterations = Integer.parseInt(args[2 - offset]);
      int numThreads = Integer.parseInt(args[3 - offset]);


      smr = new SOAPMappingRegistry();
      BeanSerializer beanSer = new BeanSerializer();

      // Map the types.
      smr.mapTypes(encodingStyleURI,
                   new QName("urn:xml-soap-address-demo", "address"),
                   Address.class, beanSer, beanSer);
      smr.mapTypes(encodingStyleURI,
                   new QName("urn:xml-soap-address-demo", "phone"),
                   PhoneNumber.class, beanSer, beanSer);

      // Fill server registry
      ComplexRequest request = new ComplexRequest();
      request.makeCall(PUT_ADDRESS_0);
      request.makeCall(PUT_ADDRESS_1);

      // Start counting time;
      long time = System.currentTimeMillis();
      for (int i=0; i<numThreads; i++) {
          Thread t = new Thread( new ComplexRequest(), "Run: " + i);
          t.start();
      }

      /// Waiting all requests to finish
      while (numberRequests > 0) {
          Thread.currentThread().sleep(100);
      }

      long  time2 = System.currentTimeMillis();
      System.out.println("Time to run " + maxIterations + " requests is " + ((time2-time)/1000.0d) + " sec ");
    }
}

