/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 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 "Axis" 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.  For more
 * information on the Apache Software Foundation, please see
 * .
 */

package rubysoapservices;


// Apache Axis imports

import org.apache.axis.AxisFault;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.utils.Options;

import org.apache.axis.MessageContext;

import org.apache.log4j.Logger;
                    
// for processing args from the command line
import org.apache.axis.utils.Options;


// xml imports

import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.*;

import org.w3c.dom.Node;
import org.w3c.dom.Document;

import java.util.*;
import java.io.*;
import java.net.URL;
import java.net.MalformedURLException;

import javax.xml.transform.*;
import javax.xml.transform.sax.*;
import javax.xml.transform.stream.*;


// saxon imports                 
import com.icl.saxon.TransformerFactoryImpl;	
import com.icl.saxon.ExtendedInputSource;



import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;


import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;



import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
import java.io.File;
import java.io.FileOutputStream;

import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;



/**
 *
 * @author Nikki Rogers (nikki.rogers@bristol.ac.uk)
 */

public class Client
{

	static Logger logger = Logger.getLogger(Client.class.getName());

	
	
        public static void main(String [] args) throws Exception
    {
        
	   
	java.util.Vector cachedSerClasses = new java.util.Vector();
	java.util.Vector cachedSerQNames = new java.util.Vector();
	java.util.Vector cachedSerFactories = new java.util.Vector();
	java.util.Vector cachedDeserFactories = new java.util.Vector();
	
	   // some bits from the autogenerated stub - ie set up class variable to hold classes to register,
	    // same with qName & also set up some variables for the various de/serialiser factories (don't
	    // need all these)
	    java.lang.Class cls;
            javax.xml.namespace.QName qName;
            java.lang.Class beansf = org.apache.axis.encoding.ser.BeanSerializerFactory.class;
            java.lang.Class beandf = org.apache.axis.encoding.ser.BeanDeserializerFactory.class;
            java.lang.Class enumsf = org.apache.axis.encoding.ser.EnumSerializerFactory.class;
            java.lang.Class enumdf = org.apache.axis.encoding.ser.EnumDeserializerFactory.class;
            java.lang.Class arraysf = org.apache.axis.encoding.ser.ArraySerializerFactory.class;
            java.lang.Class arraydf = org.apache.axis.encoding.ser.ArrayDeserializerFactory.class;
            java.lang.Class simplesf = org.apache.axis.encoding.ser.SimpleSerializerFactory.class;
            java.lang.Class simpledf = org.apache.axis.encoding.ser.SimpleDeserializerFactory.class;
	    
	// parse the command line input
	Options opts = new Options( args );
        args = opts.getRemainingArgs();

        if ( args == null ) {
          System.err.println( "Usage: ProcessRubyQuery " );
          // e.g. A query that selects ALL objects: 
	  // "select PRODUCT_NAME, VERSION, STATUS, HOMEPAGE, DOWNLOAD, LICENSE, DESC, EMAIL,OWNER_NAME, OWNER_ID, CATEGORY_MAJOR, CATEGORY_MINOR from {X} raa:product . raa:name {PRODUCT_NAME},{X} raa:product . raa:version {VERSION} , {X} raa:product . raa:status {STATUS},{X} raa:product . raa:homepage {HOMEPAGE},{X} raa:product . raa:download {DOWNLOAD},{X} raa:product . raa:license {LICENSE},{X} raa:product . raa:description {DESC},{X} raa:owner . raa:email {EMAIL} ,{X} raa:owner . raa:name {OWNER_NAME} ,{X} raa:owner . raa:id {OWNER_ID} ,{X} raa:category . raa:major {CATEGORY_MAJOR} ,{X} raa:category . raa:minor {CATEGORY_MINOR} using namespace raa = http://example.ruby-language.org/rda-vocab/test2.rdf# ";
	  // e.g. A query that selects only objects that have a PRODUCT_NAME value that is "ruby-spread":
	  // "select PRODUCT_NAME, VERSION, STATUS, HOMEPAGE, DOWNLOAD, LICENSE, DESC, EMAIL,OWNER_NAME, OWNER_ID, CATEGORY_MAJOR, CATEGORY_MINOR from {X} raa:product . raa:name {PRODUCT_NAME},{X} raa:product . raa:version {VERSION} , {X} raa:product . raa:status {STATUS},{X} raa:product . raa:homepage {HOMEPAGE},{X} raa:product . raa:download {DOWNLOAD},{X} raa:product . raa:license {LICENSE},{X} raa:product . raa:description {DESC},{X} raa:owner . raa:email {EMAIL} ,{X} raa:owner . raa:name {OWNER_NAME} ,{X} raa:owner . raa:id {OWNER_ID} ,{X} raa:category . raa:major {CATEGORY_MAJOR} ,{X} raa:category . raa:minor {CATEGORY_MINOR}  where PRODUCT_NAME like \"ruby-spread\" using namespace raa = http://example.ruby-language.org/rda-vocab/test2.rdf# ";
	  // e.g. A query that selects only objects that have a CATEGORY_MAJOR value that is "Library":
	  // "select PRODUCT_NAME,VERSION, STATUS, HOMEPAGE, DOWNLOAD, LICENSE, DESC, EMAIL,OWNER_NAME, OWNER_ID,CATEGORY_MAJOR, CATEGORY_MINOR from {X} raa:product . raa:name {PRODUCT_NAME},{X} raa:product . raa:version {VERSION} , {X} raa:product . raa:status {STATUS},{X} raa:product . raa:homepage {HOMEPAGE},{X} raa:product . raa:download {DOWNLOAD},{X} raa:product . raa:license {LICENSE},{X} raa:product . raa:description {DESC},{X} raa:owner . raa:email {EMAIL} ,{X} raa:owner . raa:name {OWNER_NAME} ,{X} raa:owner . raa:id {OWNER_ID} ,{X} raa:category . raa:major {CATEGORY_MAJOR} ,{X} raa:category . raa:minor {CATEGORY_MINOR} where CATEGORY_MAJOR like \"Library\" using namespace raa = http://example.ruby-language.org/rda-vocab/test2.rdf# "
	  System.exit(1);
        }

        String query = (String) args[0] ;
      
	// change back to port 8080 if not tunneling via the TCP monitor
	// (could make this a commandline option)
	String endpoint = "http://localhost:8081/swadWP4/services/RubySoapServiceTest";
	
        Service  service = new Service();
        
	// more from the Axis auto-gen'd client - adding classes & qnames, appropriate de/serialisation factories for each bean, into the cache 
	    qName = new javax.xml.namespace.QName("urn:rubysoapservices", "Product");
            cachedSerQNames.add(qName);
            cls = rubysoapservices.Product.class;
            cachedSerClasses.add(cls);
            cachedSerFactories.add(beansf);
            cachedDeserFactories.add(beandf);

            qName = new javax.xml.namespace.QName("urn:rubysoapservices", "RubyInfo");
            cachedSerQNames.add(qName);
            cls = rubysoapservices.RubyInfo.class;
            cachedSerClasses.add(cls);
            cachedSerFactories.add(beansf);
            cachedDeserFactories.add(beandf);

            qName = new javax.xml.namespace.QName("urn:rubysoapservices", "Category");
            cachedSerQNames.add(qName);
            cls = rubysoapservices.Category.class;
            cachedSerClasses.add(cls);
            cachedSerFactories.add(beansf);
            cachedDeserFactories.add(beandf);

            qName = new javax.xml.namespace.QName("urn:rubysoapservices", "Owner");
            cachedSerQNames.add(qName);
            cls = rubysoapservices.Owner.class;
            cachedSerClasses.add(cls);
            cachedSerFactories.add(beansf);
            cachedDeserFactories.add(beandf);

            qName = new javax.xml.namespace.QName("urn:rubysoapservices", "ArrayOfRubyInfo");
            cachedSerQNames.add(qName);
            cls = rubysoapservices.RubyInfo[].class;
            cachedSerClasses.add(cls);
            cachedSerFactories.add(arraysf);
            cachedDeserFactories.add(arraydf);
	
	
	    Call     call    = (Call) service.createCall();
        
	
        RubyInfo result = new RubyInfo();
	
	
	try {
            call.setTargetEndpointAddress( new java.net.URL(endpoint));
            call.setOperationName( new QName("urn:rubysoapservices", "rubyQuery") );
          
	    call.addParameter( "arg1", qName, ParameterMode.IN );
            
	    
	     for (int i = 0; i < cachedSerFactories.size(); ++i) {
                        cls = (java.lang.Class) cachedSerClasses.get(i);
                        qName =
                                (javax.xml.namespace.QName) cachedSerQNames.get(i);
                        java.lang.Class sf = (java.lang.Class)
                                 cachedSerFactories.get(i);
                        java.lang.Class df = (java.lang.Class)
                                 cachedDeserFactories.get(i);
                        call.registerTypeMapping(cls, qName, sf, df, false);
	     }		
	    
	    call.setReturnClass(rubysoapservices.RubyInfo[].class);
	    // set up a reference to the message context
	    MessageContext msgctxt = call.getMessageContext();
            call.invoke( new Object[] { query } );
	    
	   // drill down to the contents of the soap body
	    SOAPMessage msg = msgctxt.getMessage();
            SOAPPart sp = msg.getSOAPPart();  
            SOAPEnvelope se = sp.getEnvelope();  
            SOAPBody sb = se.getBody();      
	    
	     
	 	// The current Axis release (@2003) does not provide support for the changes to the soap encoding
		// that was originally specified in Soap 1.1.  In Soap 1.2, support of soap encoding is not obligatory.
		// Therefore we apply a stylesheet to the soap response body in order to produce the same data,
		// made compliant with soap 1.2 encoding. The stylesheet used for this has some *hacks* that are 
		// specific to this particular example
		logger.debug("XXXXXXXXXXXXXXXXXXXXXXXXXXX  GONNA TRY XSLT'ing TO SOAP 1_2 first XXXXXXXXXXXXXXXXXXx");
		logger.debug("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx");
		
		// get hold of the soap body stream
	        // using this saxon object
		ExtendedInputSource eis_a = new ExtendedInputSource(new StringReader(sb.toString()));
	   
		// get the stylesheet
		String soap1_2_stylesheet = "rubysoapservices/soap_1_1_to_1_2.xsl";	
		File soapstyleFile = new File(soap1_2_stylesheet);	
		ExtendedInputSource eis_b = new ExtendedInputSource(soapstyleFile);
		
		// get the output file ready 
		// Note that we could stream the output ready for the second (Soap -> RDF) stylesheet
		// to be applied, but we dump it out to a file for testing purposes - ie so we can
		// see the conversion to Soap 1.2 encoding
		File to_soap_1_2 = new File("rubysoapservices/transformed_to_1_2.xml");	
		FileOutputStream outs = new FileOutputStream(to_soap_1_2);	
		
				
		// Get the factory ready
		TransformerFactoryImpl factory = new TransformerFactoryImpl();
		Source soapInput = new SAXSource(factory.getSourceParser(), eis_a);
		Source style_soap = new SAXSource(factory.getSourceParser(), eis_b);
		Templates sheet1 = factory.newTemplates(style_soap);
		Transformer instance1 = sheet1.newTransformer();		
		
		// transform
	       
	       instance1.transform(soapInput,  new StreamResult(outs));
		
	
		
		logger.debug("XXXXXXXXXXXXXXXXXXXXXXXXXXX  GONNA TRY XSLT'ing SOAP TO RDF NOW XXXXXXXXXXXXXXXXXXx");
		logger.debug("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx");
		// now get that soap_1_2 output file and transform it to rdf
		
	
		// get the style sheet
		String rdf_stylesheet = "rubysoapservices/soap_to_rdf.xsl";	
		File sourcestyleFile = new File(rdf_stylesheet);	
		 ExtendedInputSource another_eis = new ExtendedInputSource(sourcestyleFile);
		 
		 // get the source input file to be transformed
		 File sourceFile = new File("rubysoapservices/transformed_to_1_2.xml");
		ExtendedInputSource eis = new ExtendedInputSource(sourceFile);
		
		// get an output file + stream ready 
		File to_rdf = new File("rubysoapservices/transformed_to_rdf_latest.xml");	
		FileOutputStream os = new FileOutputStream(to_rdf);	
		
		// Get the factory ready
		Source sourceInput = new SAXSource(factory.getSourceParser(), eis);
		Source style = new SAXSource(factory.getSourceParser(), another_eis);
		Templates sheet = factory.newTemplates(style);
		Transformer instance = sheet.newTransformer();		
		
		// transform
	       
	        instance.transform(sourceInput,  new StreamResult(os));
		
		
	    
	    // this prints out the message body just as received in the soap envelope
	    // System.out.println(sb);
	    
	    
        } catch (AxisFault fault) {
            String error = "Error : " + fault.toString();
        }
  	
	logger.debug("XXXXXXXXXXXXXXXXXXXXXXXXXXX  FINISHED TESTING RUBY SOAP SERVICE XXXXXXXXXXXXXXXXXXx");
	
    }
}