import javax.xml.rpc.*;
import javax.xml.rpc.namespace.*;
import javax.xml.rpc.encoding.*;
import com.sun.xml.rpc.encoding.*;
import com.sun.xml.rpc.wsdl.document.schema.*;
import com.sun.xml.rpc.encoding.soap.*;
import com.sun.xml.rpc.encoding.simpletype.*;


public class MathsDIIClient {

        private static final String nsXSD="http://www.w3.org/2001/XMLSchema";
        private static final String nsSOAPEncoding="http://schemas.xmlsoap.org/soap/encoding/";
        private static final String nsWSDLTarget="http://develop.com/maths/simple/arrays/wsdl";
        private static final String nsTypesTarget="http://develop.com/maths/simple/arrays/schema";

        public static void main(String[] args) {
        try {
                        ServiceFactory factory = ServiceFactory.newInstance(); 
                        QName svc = new QName(nsWSDLTarget, "MathsService");
                        Service service = factory.createService(svc); 
                        Call call = service.createCall();
                        QName port = new QName(nsWSDLTarget, "MathsIFPort");
                        call.setPortTypeName(port);
                    call.setTargetEndpointAddress(args[0]);
                        call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
                        call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
                    System.out.println("Client using DII:");
                	
                        // You must call one of these methods only (add or add1) as I cannot figure out how to register 
                        // two type mappings for the same QName.

                        // Either call this...
                        //QName primitiveDoubleArrayType = addPrimitiveDoubleArraySerializer(service);
                    //System.out.print("Answer 1: ");
                        //double[] ret = (double[])calladd(primitiveDoubleArrayType, call, port);
                        //for (int i=0;i<ret.length;i++) System.out.print(ret[i]+" ");
                    //System.out.println("");

                        // ... or this, but not both
                        QName doubleArrayType = addDoubleArraySerializer(service);
                    System.out.print("Answer 2: ");
                        Double[] ret2 = (Double[])calladd2(doubleArrayType, call, port);
                        for (int i=0;i<ret2.length;i++) System.out.print(ret2[i].doubleValue()+" ");
                    System.out.println("");
                } catch (Exception ex) {
                ex.printStackTrace();
                }
        }
        private static Object calladd(QName type, Call call, QName port) throws Exception {
                QName op = new QName(nsWSDLTarget, "add");
                call.setOperationName(op);
                boolean specNeeded = call.isParameterAndReturnSpecRequired(op);
                if (specNeeded) {
                        call.removeAllParameters();
                        call.addParameter("arrayOfdouble_1", type, ParameterMode.PARAM_MODE_IN);
                        call.addParameter("arrayOfdouble_2", type, ParameterMode.PARAM_MODE_IN);
                        call.setReturnType(type);
                }
                Object[] params = {new double[] {1.0, 2.6}, new double[] {10.0, 26.0}};
                Object ret = call.invoke(params);
                return ret;
        }
        private static Object calladd2(QName type, Call call, QName port) throws Exception {
                QName op = new QName(nsWSDLTarget, "add2");
                call.setOperationName(op);
                boolean specNeeded = call.isParameterAndReturnSpecRequired(op);
                if (specNeeded) {
                        call.removeAllParameters();
                        call.addParameter("arrayOfDouble_1", type, ParameterMode.PARAM_MODE_IN);
                        call.addParameter("arrayOfDouble_2", type, ParameterMode.PARAM_MODE_IN);
                        call.setReturnType(type);
                }
                Object[] params = {new Double[] {new Double(1.0), new Double(2.6)}, 
                        new Double[] {new Double(10.0), new Double(26.0)}};
                Object ret = call.invoke(params);
                return ret;
        }
        private static QName addPrimitiveDoubleArraySerializer(Service service) throws Exception {
                TypeMapping mapping = service.getTypeMappingRegistry().getTypeMapping(SOAPConstants.NS_SOAP_ENCODING);

            QName type = new QName(nsTypesTarget, "ArrayOfdouble");
            QName elemName = new QName("", "double");
            CombinedSerializer serializerelemSerializer = new SimpleTypeSerializer(SchemaConstants.QNAME_TYPE_DOUBLE,
                        SerializerConstants.ENCODE_TYPE, SerializerConstants.NULLABLE, SOAPConstants.NS_SOAP_ENCODING, 
                        XSDDoubleEncoder.getInstance());
            CombinedSerializer serializer = new SimpleTypeArraySerializer(type, SerializerConstants.ENCODE_TYPE, 
                        SerializerConstants.NULLABLE, SOAPConstants.NS_SOAP_ENCODING, elemName, 
                        SchemaConstants.QNAME_TYPE_DOUBLE, double.class, 1, null, 
                        (SimpleTypeSerializer)serializerelemSerializer);
            serializer = new ReferenceableSerializerImpl(SerializerConstants.SERIALIZE_AS_REF, serializer);
            registerSerializer(mapping,double[].class, type, serializer);
                return type;
        }
        private static QName addDoubleArraySerializer(Service service) throws Exception {
                TypeMapping mapping = service.getTypeMappingRegistry().getTypeMapping(SOAPConstants.NS_SOAP_ENCODING);

            QName type = new QName(nsTypesTarget, "ArrayOfdouble");
            QName elemName = new QName("", "double");
            CombinedSerializer serializer = new ObjectArraySerializer(type,
                SerializerConstants.ENCODE_TYPE, SerializerConstants.NULLABLE, SOAPConstants.NS_SOAP_ENCODING, 
                elemName, SOAPConstants.QNAME_TYPE_DOUBLE, java.lang.Double.class, 1, null);
            serializer = new ReferenceableSerializerImpl(SerializerConstants.SERIALIZE_AS_REF, serializer);
            registerSerializer(mapping,java.lang.Double[].class, type, serializer);
                return type;
        }
        private static void registerSerializer(TypeMapping mapping, Class javaType, QName xmlType, Serializer ser) {
                /*
                System.out.println("Adding [de]serializer for type mapping ("+xmlType+","+javaType+")");
                if (mapping.isRegistered(javaType,xmlType))
                        System.out.println("Warning: [de]serializer already registered for type mapping ("+
                                xmlType+","+javaType+")");
                */
                mapping.register(javaType, xmlType, new SingletonSerializerFactory(ser),
                        new SingletonDeserializerFactory((Deserializer)ser));
                //System.out.println("Added [de]serializer for type mapping ("+xmlType+","+javaType+")");
        }
        private static void unregisterSerializer(TypeMapping mapping, Class javaType, QName xmlType) {
                //System.out.println("Removing [de]serializer for type mapping ("+xmlType+","+javaType+")");
                mapping.removeSerializer(javaType, xmlType);
                mapping.removeDeserializer(javaType, xmlType);
                /*
                if (mapping.isRegistered(javaType,xmlType))
                        System.out.println("Warning: [de]serializer not removed for type mapping ("+xmlType+","+javaType+")");
                else
                        System.out.println("[de]serializer removed for type mapping ("+xmlType+","+javaType+")");
                */
        }
}