Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
169 views
in Technique[技术] by (71.8m points)

android - How to create SOAP request via ksoap2

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header/>
    <S:Body>
        <ns2:FReadStatus xmlns:ns2="http://poweb13/">
            <arg0>000D6F0000</arg0>
        </ns2:FReadStatus>
    </S:Body>
</S:Envelope>

i'm working in an android project which i want to consume some JAX-WS. The services are made by someone else so i can't change anything of them.I want to sent the above SOAP message with this written code but the only thing i receive when call them is java.lang.NullPointerException

private static final String NAMESPACE = "http://poweb13/";
private static final String URL = "http://smart.gr:8080/aWESoME/SmartPlugService?wsdl"; 
private static final String SOAP_ACTION = "SmartPlugService";
private static final String METHOD_NAME = "FReadStatus";
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); 
PropertyInfo p1 = new PropertyInfo();
p1.setName("MAC");
p1.setValue("000D6F0000");
p1.setType(myDevice.getmac().toString().getClass());
request.addProperty(p1);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); 
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {           
    androidHttpTransport.setXmlVersionTag("<?xml version="1.0" encoding="UTF-8"?>");                 
    androidHttpTransport.call(SOAP_ACTION, envelope);
    SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;
    String result=resultsRequestSOAP.getProperty("return").toString();
    Log.i("info","Received :" + result);
} catch (java.lang.ClassCastException e){
    SoapFault fault=(SoapFault)envelope.bodyIn;
    Log.e("error","Received :" + fault.getMessage().toString());
    Log.e("error","Received :" + fault.getLocalizedMessage().toString());
    StackTraceElement[] st=fault.getStackTrace();
    for(int i=0;i<st.length;i++){
        Log.e("error","Received :" +st[i] );
    }
} catch (Exception e) {
    Log.e("error","smthing went wrong!!");
    e.printStackTrace();
}

I think that it doesn't create a xml document even, but i don't know how to check it. I tried to create a XmlSerializer to put data for creating xml but i also receive a NullPointerException. So can anyone help me about how to code the above request? here's some parts of wsdl file

<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://poweb13/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://poweb13/" name="SmartPlugService">
<types>
<xsd:schema>
<xsd:import namespace="http://poweb13/" schemaLocation="http://smart.gr:8080/aWESoME/SmartPlugService?xsd=1"/>
</xsd:schema>
</types>


<message name="FReadStatus">
<part name="parameters" element="tns:FReadStatus"/>
</message>
...
<portType name="SmartPlugService">
<operation name="FReadStatus">
...
<input wsam:Action="http://poweb13/SmartPlugService/FReadStatusRequest" message="tns:FReadStatus"/>
<output wsam:Action="http://poweb13/SmartPlugService/FReadStatusResponse" message="tns:FReadStatusResponse"/>
<fault message="tns:InvalidDeviceAddressException" name="InvalidDeviceAddressException" wsam:Action="http://poweb13/SmartPlugService/FReadStatus/Fault/InvalidDeviceAddressException"/>
<fault message="tns:InternalServiceException" name="InternalServiceException" wsam:Action="http://poweb13/SmartPlugService/FReadStatus/Fault/InternalServiceException"/>
...
</operation>
</portType>
<binding name="SmartPlugServicePortBinding" type="tns:SmartPlugService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
...
<operation name="FReadStatus">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="InvalidDeviceAddressException">
<soap:fault name="InvalidDeviceAddressException" use="literal"/>
</fault>
<fault name="InternalServiceException">
<soap:fault name="InternalServiceException" use="literal"/>
</fault>
</operation>
...
</binding>

Some parts of xsd file

<xs:schema xmlns:tns="http://poweb13/" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://poweb13/">
<xs:element name="FReadStatus" type="tns:FReadStatus"/>
<xs:complexType name="FReadStatus">
<xs:sequence>
<xs:element name="arg0" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

i should have a SOAP response like this:

SOAP Response

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:FReadStatusResponse xmlns:ns2="http://poweb13/">
            <return>1</return>
        </ns2:FReadStatusResponse>
    </S:Body>
</S:Envelope>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Ok so you have a function FReadStatus:

<message name="FReadStatus">
  <part name="parameters" element="tns:FReadStatus"/>
</message>

which has an element FReadStatus of complex type(ie object, which is a class found on the server).
This complex type has an attribute arg0 of type String. Its definition is:

<xs:complexType name="FReadStatus">
  <xs:sequence>
    <xs:element name="arg0" type="xs:string" minOccurs="0"/>
  </xs:sequence>
</xs:complexType>

So you will need to create a local class that implements kvmSerializable to map this complex type to its corresponding class on the server, so you will do :

public class FReadStatus implements KvmSerializable {

String mac; 

@Override
public Object getProperty(int arg0) {
switch (arg0){
    case 0:
        return mac;
    default:
        return null;
        }
}

@Override
public int getPropertyCount() {
    return 1;//because you have 1 parameter
}

@Override
public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {
switch(arg0)
{

    case 0:
        arg2.type = PropertyInfo.STRING_CLASS;//because its type is string
        arg2.name = "arg0";
        break;
    default:break;
}

}

@Override
public void setProperty(int arg0, Object arg1) {
switch(arg0)
{
    case 0:
        mac=  (String)arg1;
        break;
    default:
        break;
}
}

Now that you have the class , you will do the following in the code you had:

    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); 

    PropertyInfo pi = new PropertyInfo();
    pi.setName("arg0");
    pi.setValue("000D6F0000");
    pi.setType(FReadStatus .class);
    request.addProperty(pi);

    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); 
    envelope.setOutputSoapObject(request);

     //Now you have to add mapping to map the local class created, to the one on the server
    envelope.addMapping(NAMESPACE , FReadStatus.class.getSimpleName(), FReadStatus .class);

    // Add marshalling (this one might not be necessary, but ill just add it)
    Marshal floatMarshal = new MarshalFloat();
    floatMarshal.register(envelope);

    AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);//AndroidHttpTransport INSTEAD OF HttpTransportSE 

    androidHttpTransport.debug = true;//NEW ADDED
    try {           

        androidHttpTransport.call(SOAP_ACTION, envelope);

       //Important Outputs to check how the request/Response looks like.. Check them in Logcat to find these outputs
       System.out.println("requestDump is :"+androidHttpTransport.requestDump);
       System.out.println("responseDump is :"+androidHttpTransport.responseDump);
       System.out.println("response"+envelope.getResponse());

    } catch (Exception e){}

Let me know wt happens. You must use Logcat to check requestDump and responseDump

UPDATE: answering your question about UnknowHostException
possible causes and solutions

  • Check if in your AndroidManifest.xml you have :

    <uses-permission android:name="android.permission.INTERNET" />
    
  • If you are using an emulator do as mentioned in this link

  • If you are behind a proxy do :

    System.setProperty("http.proxyHost", "my.proxyhost.com");
    System.setProperty("http.proxyPort", "1234");
    
  • You might need to use warmup the dns , check this link


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...