| From b5b548a4be9f1ced6f5599b62765216f9ab8af00 Mon Sep 17 00:00:00 2001 |
| From: Ecco Park <eccopark@google.com> |
| Date: Tue, 8 May 2018 13:44:14 -0700 |
| Subject: [PATCH 1/1] ksoap2 update |
| |
| Change-Id: Iace4c0f3cb31c9532c5fa0c44c2dc863bd81b23e |
| Signed-off-by: Ecco Park <eccopark@google.com> |
| --- |
| .../main/java/org/ksoap2/SoapEnvelope.java | 17 +- |
| .../src/main/java/org/ksoap2/SoapFault12.java | 13 +- |
| .../serialization/AttributeContainer.java | 128 +++++- |
| .../java/org/ksoap2/serialization/DM.java | 57 ++- |
| .../ksoap2/serialization/HasAttributes.java | 16 + |
| .../ksoap2/serialization/HasInnerText.java | 17 + |
| .../ksoap2/serialization/KvmSerializable.java | 25 +- |
| .../org/ksoap2/serialization/Marshal.java | 3 +- |
| .../ksoap2/serialization/MarshalBase64.java | 3 +- |
| .../org/ksoap2/serialization/MarshalDate.java | 3 +- |
| .../serialization/MarshalHashtable.java | 8 +- |
| .../org/ksoap2/serialization/SoapObject.java | 340 +++++++++++++- |
| .../ksoap2/serialization/SoapPrimitive.java | 20 +- |
| .../SoapSerializationEnvelope.java | 419 ++++++++++++------ |
| .../org/ksoap2/serialization/ValueWriter.java | 13 + |
| .../ksoap2/transport/ServiceConnection.java | 13 +- |
| .../java/org/ksoap2/transport/Transport.java | 131 ++++-- |
| .../ksoap2/serialization/MarshalFloat.java | 3 +- |
| .../transport/HttpResponseException.java | 60 +++ |
| .../org/ksoap2/transport/HttpTransportSE.java | 348 +++++++-------- |
| .../transport/HttpsServiceConnectionSE.java | 58 ++- |
| .../ksoap2/transport/HttpsTransportSE.java | 81 ++-- |
| .../transport/KeepAliveHttpsTransportSE.java | 20 +- |
| .../ksoap2/transport/ServiceConnectionSE.java | 44 +- |
| 24 files changed, 1298 insertions(+), 542 deletions(-) |
| create mode 100644 ksoap2-base/src/main/java/org/ksoap2/serialization/HasAttributes.java |
| create mode 100644 ksoap2-base/src/main/java/org/ksoap2/serialization/HasInnerText.java |
| create mode 100644 ksoap2-base/src/main/java/org/ksoap2/serialization/ValueWriter.java |
| create mode 100644 ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpResponseException.java |
| |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java b/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java |
| index 8a0b894..1c43656 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java |
| @@ -54,10 +54,8 @@ public class SoapEnvelope { |
| /** Namespace constant: http://www.w3.org/1999/XMLSchema */ |
| public static final String XSI1999 = "http://www.w3.org/1999/XMLSchema-instance"; |
| |
| - //public static final String NS20 = "http://www.wi-fi-org/specifications/hotspot2dot0/spp/1.0/"; |
| public static final String NS20 = "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"; |
| |
| - //public static final String OMADM12 = "http://www.openmobilealliance.org/tech/DTD/dm_ddf-v1_2.dtd"; |
| |
| /** |
| * Returns true for the string values "1" and "true", ignoring upper/lower |
| @@ -105,9 +103,8 @@ public class SoapEnvelope { |
| /** Xml Schema data namespace, set by the constructor */ |
| public String xsd; |
| |
| - ///M: HS20 Add by Jungo |
| + // HS20 change |
| public String ns; |
| - public String omadm; |
| |
| /** |
| * Initializes a SOAP Envelope. The version parameter must be set to one of |
| @@ -129,10 +126,8 @@ public class SoapEnvelope { |
| enc = SoapEnvelope.ENC2003; |
| env = SoapEnvelope.ENV2003; |
| } |
| - |
| + // HS20 change |
| ns = SoapEnvelope.NS20; |
| - //omadm = SoapEnvelope.OMADM12; |
| - |
| } |
| |
| /** Parses the SOAP envelope from the given parser */ |
| @@ -206,13 +201,9 @@ public class SoapEnvelope { |
| * given XML writer. |
| */ |
| public void write(XmlSerializer writer) throws IOException { |
| - ///M: HS20 modify by Jungo |
| - //writer.setPrefix("i", xsi); |
| - //writer.setPrefix("d", xsd); |
| - //writer.setPrefix("c", enc); |
| - writer.setPrefix("soap", env);//the prefix for namespace env in xml output |
| + // HS 2.0 changes |
| + writer.setPrefix("soap", env); //the prefix for namespace env in xml output |
| writer.setPrefix("spp", ns); |
| - //writer.setPrefix("omadm", omadm); |
| |
| writer.startTag(env, "Envelope"); |
| writer.startTag(env, "Header"); |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/SoapFault12.java b/ksoap2-base/src/main/java/org/ksoap2/SoapFault12.java |
| index 5667cb4..3f39147 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/SoapFault12.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/SoapFault12.java |
| @@ -72,27 +72,28 @@ public class SoapFault12 extends SoapFault { |
| |
| while (parser.nextTag() == XmlPullParser.START_TAG) { |
| String name = parser.getName(); |
| + String namespace = parser.getNamespace(); |
| parser.nextTag(); |
| - if (name.equals("Code")) { |
| + if (name.toLowerCase().equals("Code".toLowerCase())) { |
| this.Code = new Node(); |
| this.Code.parse(parser); |
| - } else if (name.equals("Reason")) { |
| + } else if (name.toLowerCase().equals("Reason".toLowerCase())) { |
| this.Reason = new Node(); |
| this.Reason.parse(parser); |
| - } else if (name.equals("Node")) { |
| + } else if (name.toLowerCase().equals("Node".toLowerCase())) { |
| this.Node = new Node(); |
| this.Node.parse(parser); |
| - } else if (name.equals("Role")) { |
| + } else if (name.toLowerCase().equals("Role".toLowerCase())) { |
| this.Role = new Node(); |
| this.Role.parse(parser); |
| - } else if (name.equals("Detail")) { |
| + } else if (name.toLowerCase().equals("Detail".toLowerCase())) { |
| this.Detail = new Node(); |
| this.Detail.parse(parser); |
| } else { |
| throw new RuntimeException("unexpected tag:" + name); |
| } |
| |
| - parser.require(XmlPullParser.END_TAG, SoapEnvelope.ENV2003, name); |
| + parser.require(XmlPullParser.END_TAG, namespace, name); |
| } |
| parser.require(XmlPullParser.END_TAG, SoapEnvelope.ENV2003, "Fault"); |
| parser.nextTag(); |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeContainer.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeContainer.java |
| index 6b83847..34d2723 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeContainer.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeContainer.java |
| @@ -3,8 +3,8 @@ package org.ksoap2.serialization; |
| |
| import java.util.Vector; |
| |
| -public class AttributeContainer { |
| - private Vector attributes = new Vector(); |
| +public class AttributeContainer implements HasAttributes{ |
| + protected Vector attributes = new Vector(); |
| |
| /** |
| * Places AttributeInfo of desired attribute into a designated AttributeInfo object |
| @@ -29,9 +29,9 @@ public class AttributeContainer { |
| return ((AttributeInfo) attributes.elementAt(index)).getValue(); |
| } |
| |
| - /** |
| - * Get the attribute's toString value. |
| - */ |
| + /** |
| + * Get the attribute's toString value. |
| + */ |
| public String getAttributeAsString(int index) { |
| AttributeInfo attributeInfo = (AttributeInfo) attributes.elementAt(index); |
| return attributeInfo.getValue().toString(); |
| @@ -51,6 +51,20 @@ public class AttributeContainer { |
| } |
| } |
| |
| + /** |
| + * Get the attribute with the given name |
| + * |
| + * @throws RuntimeException if the attribute does not exist |
| + */ |
| + public Object getAttribute(String namespace,String name) { |
| + Integer i = attributeIndex(namespace,name); |
| + if (i != null) { |
| + return getAttribute(i.intValue()); |
| + } else { |
| + throw new RuntimeException("illegal property: " + name); |
| + } |
| + } |
| + |
| /** |
| * Get the toString value of the attribute with the given name. |
| * |
| @@ -65,6 +79,19 @@ public class AttributeContainer { |
| } |
| } |
| |
| + /** |
| + * Get the toString value of the attribute with the given name. |
| + * |
| + * @throws RuntimeException if the attribute does not exist |
| + */ |
| + public String getAttributeAsString(String namespace,String name) { |
| + Integer i = attributeIndex(namespace,name); |
| + if (i != null) { |
| + return getAttribute(i.intValue()).toString(); |
| + } else { |
| + throw new RuntimeException("illegal property: " + name); |
| + } |
| + } |
| /** |
| * Knows whether the given attribute exists |
| */ |
| @@ -76,6 +103,16 @@ public class AttributeContainer { |
| } |
| } |
| |
| + /** |
| + * Knows whether the given attribute exists |
| + */ |
| + public boolean hasAttribute(final String namespace,final String name) { |
| + if (attributeIndex(namespace,name) != null) { |
| + return true; |
| + } else { |
| + return false; |
| + } |
| + } |
| /** |
| * Get an attribute without chance of throwing an exception |
| * |
| @@ -91,6 +128,21 @@ public class AttributeContainer { |
| } |
| } |
| |
| + /** |
| + * Get an attribute without chance of throwing an exception |
| + * |
| + * @param name the name of the attribute to retrieve |
| + * @return the value of the attribute if it exists; {@code null} if it does not exist |
| + */ |
| + public Object getAttributeSafely(String namespace,String name) { |
| + Integer i = attributeIndex(namespace,name); |
| + if (i != null) { |
| + return getAttribute(i.intValue()); |
| + } else { |
| + return null; |
| + } |
| + } |
| + |
| /** |
| * Get an attributes' toString value without chance of throwing an |
| * exception. |
| @@ -108,6 +160,23 @@ public class AttributeContainer { |
| } |
| } |
| |
| + /** |
| + * Get an attributes' toString value without chance of throwing an |
| + * exception. |
| + |
| + * @param name |
| + * @return the value of the attribute,s toString method if it exists; "" |
| + * if it does not exist |
| + */ |
| + public Object getAttributeSafelyAsString(String namespace,String name) { |
| + Integer i = attributeIndex(namespace,name); |
| + if (i != null) { |
| + return getAttribute(i.intValue()).toString(); |
| + } else { |
| + return ""; |
| + } |
| + } |
| + |
| private Integer attributeIndex(String name) { |
| for (int i = 0; i < attributes.size(); i++) { |
| if (name.equals(((AttributeInfo) attributes.elementAt(i)).getName())) { |
| @@ -117,6 +186,16 @@ public class AttributeContainer { |
| return null; |
| } |
| |
| + private Integer attributeIndex(String namespace,String name) { |
| + for (int i = 0; i < attributes.size(); i++) { |
| + AttributeInfo attrInfo=(AttributeInfo) attributes.elementAt(i); |
| + if (name.equals(attrInfo.getName()) && namespace.equals(attrInfo.getNamespace())) { |
| + return new Integer(i); |
| + } |
| + } |
| + return null; |
| + } |
| + |
| /** |
| * Returns the number of attributes |
| * |
| @@ -160,13 +239,25 @@ public class AttributeContainer { |
| * @return {@code this} object. |
| */ |
| public void addAttribute(String name, Object value) { |
| + addAttribute(null,name,value); |
| + } |
| + |
| + /** |
| + * Adds a attribute (parameter) to the object. |
| + * |
| + * @param namespace The namespace of the attribute |
| + * @param name The name of the attribute |
| + * @param value the value of the attribute |
| + * @return {@code this} object. |
| + */ |
| + public void addAttribute(String namespace,String name, Object value) { |
| AttributeInfo attributeInfo = new AttributeInfo(); |
| attributeInfo.name = name; |
| + attributeInfo.namespace = namespace; |
| attributeInfo.type = value == null ? PropertyInfo.OBJECT_CLASS : value.getClass(); |
| attributeInfo.value = value; |
| addAttribute(attributeInfo); |
| } |
| - |
| /** |
| * Add an attribute if the value is not null. |
| * @param name |
| @@ -178,6 +269,18 @@ public class AttributeContainer { |
| } |
| } |
| |
| + /** |
| + * Add an attribute if the value is not null. |
| + * @param namespace The namespace of the attribute |
| + * @param name |
| + * @param value |
| + */ |
| + public void addAttributeIfValue(String namespace,String name, Object value) { |
| + if (value != null) { |
| + addAttribute(namespace,name, value); |
| + } |
| + } |
| + |
| /** |
| * Add a new attribute by providing an {@link AttributeInfo} object. {@code AttributeInfo} |
| * contains all data about the attribute, including name and value.} |
| @@ -198,4 +301,17 @@ public class AttributeContainer { |
| attributes.addElement(attributeInfo); |
| } |
| } |
| + |
| + |
| + public void setAttribute(AttributeInfo info) { |
| + |
| + |
| + } |
| + |
| + |
| + public void getAttribute(int index, AttributeInfo info) { |
| + |
| + |
| + } |
| + |
| } |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/DM.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/DM.java |
| index 78d4449..255126e 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/DM.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/DM.java |
| @@ -20,9 +20,12 @@ |
| |
| package org.ksoap2.serialization; |
| |
| -import java.io.*; |
| -import org.xmlpull.v1.*; |
| -import org.ksoap2.*; |
| +import java.io.IOException; |
| + |
| +import org.ksoap2.SoapEnvelope; |
| +import org.xmlpull.v1.XmlPullParser; |
| +import org.xmlpull.v1.XmlPullParserException; |
| +import org.xmlpull.v1.XmlSerializer; |
| |
| /** |
| * This class is not public, so save a few bytes by using a short class name (DM |
| @@ -30,8 +33,7 @@ import org.ksoap2.*; |
| */ |
| class DM implements Marshal { |
| |
| - public Object readInstance(XmlPullParser parser, String namespace, String name, |
| - PropertyInfo expected) |
| + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo excepted) |
| throws IOException, XmlPullParserException { |
| String text = parser.nextText(); |
| switch (name.charAt(0)) { |
| @@ -49,9 +51,10 @@ class DM implements Marshal { |
| } |
| |
| /** |
| - * Write the instance out. In case it is an AttributeContainer write those our first though. |
| - * @param writer |
| - * the xml serializer. |
| + * Write the instance out. In case it is an AttributeContainer write those our first though. |
| + * If it HasAttributes then write the attributes and values. |
| + * |
| + * @param writer the xml serializer. |
| * @param instance |
| * @throws IOException |
| */ |
| @@ -62,11 +65,43 @@ class DM implements Marshal { |
| for (int counter = 0; counter < cnt; counter++) { |
| AttributeInfo attributeInfo = new AttributeInfo(); |
| attributeContainer.getAttributeInfo(counter, attributeInfo); |
| - writer.attribute(attributeInfo.getNamespace(), attributeInfo.getName(), |
| - attributeInfo.getValue().toString()); |
| + try { |
| + attributeContainer.getAttribute(counter, attributeInfo); |
| + } catch (Exception e) { |
| + e.printStackTrace(); |
| + } |
| + if (attributeInfo.getValue() != null) { |
| + writer.attribute(attributeInfo.getNamespace(), attributeInfo.getName(), |
| + (attributeInfo.getValue() != null) ? attributeInfo.getValue().toString() : ""); |
| + } |
| + } |
| + } else if (instance instanceof HasAttributes) { |
| + HasAttributes soapObject = (HasAttributes) instance; |
| + int cnt = soapObject.getAttributeCount(); |
| + for (int counter = 0; counter < cnt; counter++) { |
| + AttributeInfo attributeInfo = new AttributeInfo(); |
| + soapObject.getAttributeInfo(counter, attributeInfo); |
| + try { |
| + soapObject.getAttribute(counter, attributeInfo); |
| + } catch (Exception e) { |
| + e.printStackTrace(); |
| + } |
| + if (attributeInfo.getValue() != null) { |
| + writer.attribute(attributeInfo.getNamespace(), attributeInfo.getName(), |
| + attributeInfo.getValue() != null ? attributeInfo.getValue().toString() : ""); |
| + } |
| } |
| } |
| - writer.text(instance.toString()); |
| + |
| + if(instance instanceof ValueWriter) |
| + { |
| + ((ValueWriter)instance).write(writer); |
| + } |
| + else |
| + { |
| + writer.text(instance.toString()); |
| + } |
| + |
| } |
| |
| public void register(SoapSerializationEnvelope cm) { |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/HasAttributes.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/HasAttributes.java |
| new file mode 100644 |
| index 0000000..b513138 |
| --- /dev/null |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/HasAttributes.java |
| @@ -0,0 +1,16 @@ |
| +package org.ksoap2.serialization;
|
| +
|
| +/**
|
| + * Common inteface for classes which want to serialize attributes to outgoing soap message
|
| + *
|
| + * @author robocik
|
| + */
|
| +public interface HasAttributes {
|
| + int getAttributeCount();
|
| +
|
| + void getAttributeInfo(int index, AttributeInfo info);
|
| +
|
| + void getAttribute(int index, AttributeInfo info);
|
| +
|
| + void setAttribute(AttributeInfo info);
|
| +}
|
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/HasInnerText.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/HasInnerText.java |
| new file mode 100644 |
| index 0000000..b35c35b |
| --- /dev/null |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/HasInnerText.java |
| @@ -0,0 +1,17 @@ |
| +package org.ksoap2.serialization; |
| +/** |
| + * Interface for classes requiring inner text of xml tags |
| + * |
| + * @author satansly |
| + */ |
| +public interface HasInnerText { |
| + /** |
| + * Gets the inner text of xml tags |
| + */ |
| + Object getInnerText(); |
| + |
| + /** |
| + * @param s String to be set as inner text for an outgoing soap object |
| + */ |
| + void setInnerText(Object s); |
| +} |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/KvmSerializable.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/KvmSerializable.java |
| index bded0c0..09d7b32 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/KvmSerializable.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/KvmSerializable.java |
| @@ -39,31 +39,26 @@ public interface KvmSerializable { |
| */ |
| Object getProperty(int index); |
| |
| - /** |
| - * @return the number of serializable properties |
| + /** |
| + * @return the number of serializable properties |
| */ |
| int getPropertyCount(); |
| |
| /** |
| * Sets the property with the given index to the given value. |
| - * |
| - * @param index |
| - * the index to be set |
| - * @param value |
| - * the value of the property |
| + * |
| + * @param index the index to be set |
| + * @param value the value of the property |
| */ |
| void setProperty(int index, Object value); |
| |
| /** |
| * Fills the given property info record. |
| - * |
| - * @param index |
| - * the index to be queried |
| - * @param properties |
| - * information about the (de)serializer. Not frequently used. |
| - * @param info |
| - * The return parameter, to be filled with information about the |
| - * property with the given index. |
| + * |
| + * @param index the index to be queried |
| + * @param properties information about the (de)serializer. Not frequently used. |
| + * @param info The return parameter, to be filled with information about the |
| + * property with the given index. |
| */ |
| void getPropertyInfo(int index, Hashtable properties, PropertyInfo info); |
| |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/Marshal.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/Marshal.java |
| index cfa9d81..100f107 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/Marshal.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/Marshal.java |
| @@ -41,8 +41,7 @@ public interface Marshal { |
| * the namespace. |
| * @return the object read from the xml stream. |
| */ |
| - public Object readInstance(XmlPullParser parser, String namespace, String name, |
| - PropertyInfo expected) |
| + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) |
| throws IOException, XmlPullParserException; |
| |
| /** |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalBase64.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalBase64.java |
| index 2f8420c..2239027 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalBase64.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalBase64.java |
| @@ -31,8 +31,7 @@ import org.xmlpull.v1.*; |
| public class MarshalBase64 implements Marshal { |
| public static Class BYTE_ARRAY_CLASS = new byte[0].getClass(); |
| |
| - public Object readInstance(XmlPullParser parser, String namespace, String name, |
| - PropertyInfo expected) |
| + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) |
| throws IOException, XmlPullParserException { |
| return Base64.decode(parser.nextText()); |
| } |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalDate.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalDate.java |
| index 3e4fa06..489ba3b 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalDate.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalDate.java |
| @@ -31,8 +31,7 @@ import org.ksoap2.kobjects.isodate.*; |
| public class MarshalDate implements Marshal { |
| public static Class DATE_CLASS = new Date().getClass(); |
| |
| - public Object readInstance(XmlPullParser parser, String namespace, String name, |
| - PropertyInfo expected) |
| + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) |
| throws IOException, XmlPullParserException { |
| return IsoDate.stringToDate(parser.nextText(), IsoDate.DATE_TIME); |
| } |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalHashtable.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalHashtable.java |
| index d2367e9..0c6b53e 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalHashtable.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalHashtable.java |
| @@ -46,8 +46,7 @@ public class MarshalHashtable implements Marshal { |
| public static final Class HASHTABLE_CLASS = new Hashtable().getClass(); |
| SoapSerializationEnvelope envelope; |
| |
| - public Object readInstance(XmlPullParser parser, String namespace, String name, |
| - PropertyInfo expected) |
| + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) |
| throws IOException, XmlPullParserException { |
| Hashtable instance = new Hashtable(); |
| String elementName = parser.getName(); |
| @@ -81,7 +80,7 @@ public class MarshalHashtable implements Marshal { |
| Object key = keys.nextElement(); |
| item.setProperty(0, key); |
| item.setProperty(1, h.get(key)); |
| - envelope.writeObjectBody(writer, item); |
| + envelope.writeObjectBodyWithAttributes(writer, item); |
| writer.endTag("", "item"); |
| } |
| } |
| @@ -89,7 +88,6 @@ public class MarshalHashtable implements Marshal { |
| class ItemSoapObject extends SoapObject { |
| Hashtable h; |
| int resolvedIndex = -1; |
| - |
| ItemSoapObject(Hashtable h) { |
| super(null, null); |
| this.h = h; |
| @@ -107,7 +105,7 @@ public class MarshalHashtable implements Marshal { |
| Object resolved = resolvedIndex == 0 ? getProperty(0) : getProperty(1); |
| if (index == 0) { |
| h.put(value, resolved); |
| - } else { |
| + } else { |
| h.put(resolved, value); |
| } |
| } |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapObject.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapObject.java |
| index 24a1ffe..f11210a 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapObject.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapObject.java |
| @@ -38,7 +38,7 @@ import java.util.*; |
| * KvmSerializable interface. |
| */ |
| |
| -public class SoapObject extends AttributeContainer implements KvmSerializable { |
| +public class SoapObject extends AttributeContainer implements KvmSerializable, HasInnerText { |
| |
| private static final String EMPTY_STRING = ""; |
| /** |
| @@ -54,6 +54,8 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| */ |
| protected Vector properties = new Vector(); |
| |
| + protected Object innerText; |
| + |
| // TODO: accessing properties and attributes would work much better if we |
| // kept a list of known properties instead of iterating through the list |
| // each time |
| @@ -181,6 +183,230 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| } |
| } |
| |
| + /** |
| + * Get the property with the given name |
| + * |
| + * return null |
| + * if the property does not exist |
| + */ |
| + public Object getProperty(String namespace,String name) { |
| + Integer index = propertyIndex(namespace,name); |
| + if (index != null) { |
| + return getProperty(index.intValue()); |
| + } |
| + else { |
| + throw new RuntimeException("illegal property: " + name); |
| + } |
| + } |
| + |
| + /** |
| + * Get a property using namespace and name without chance of throwing an exception |
| + * |
| + * @return the property if it exists; if not, {@link NullSoapObject} is |
| + * returned |
| + */ |
| + public Object getPropertyByNamespaceSafely(final String namespace, final String name) { |
| + Integer i = propertyIndex(namespace,name); |
| + if (i != null) { |
| + return getProperty(i.intValue()); |
| + } else { |
| + return new NullSoapObject(); |
| + } |
| + } |
| + |
| + /** |
| + * Get the toString value of a property without chance of throwing an |
| + * exception |
| + * |
| + * @return the string value of the property if it exists; if not, #EMPTY_STRING is |
| + * returned |
| + */ |
| + public String getPropertyByNamespaceSafelyAsString(final String namespace,final String name) { |
| + Integer i = propertyIndex(namespace,name); |
| + if (i != null) { |
| + Object foo = getProperty(i.intValue()); |
| + if (foo == null) { |
| + return EMPTY_STRING; |
| + } else { |
| + return foo.toString(); |
| + } |
| + } else { |
| + return EMPTY_STRING; |
| + } |
| + } |
| + |
| + /** |
| + * Get a property without chance of throwing an exception. An object can be |
| + * provided to this method; if the property is not found, this object will |
| + * be returned. |
| + * |
| + * @param defaultThing |
| + * the object to return if the property is not found |
| + * @return the property if it exists; defaultThing if the property does not |
| + * exist |
| + */ |
| + public Object getPropertySafely(final String namespace,final String name, final Object defaultThing) { |
| + Integer i = propertyIndex(namespace,name); |
| + if (i != null) { |
| + return getProperty(i.intValue()); |
| + } else { |
| + return defaultThing; |
| + } |
| + } |
| + |
| + /** |
| + * Get the toString value of a property without chance of throwing an |
| + * exception. An object can be provided to this method; if the property is |
| + * not found, this object's string representation will be returned. |
| + * |
| + * @param defaultThing |
| + * toString of the object to return if the property is not found |
| + * @return the property toString if it exists; defaultThing toString if the |
| + * property does not exist, if the defaultThing is null #EMPTY_STRING |
| + * is returned |
| + */ |
| + public String getPropertySafelyAsString(final String namespace,final String name, |
| + final Object defaultThing) { |
| + Integer i = propertyIndex(namespace,name); |
| + if (i != null) { |
| + Object property = getProperty(i.intValue()); |
| + if (property != null) { |
| + return property.toString(); |
| + } else { |
| + return EMPTY_STRING; |
| + } |
| + } else { |
| + if (defaultThing != null) { |
| + return defaultThing.toString(); |
| + } else { |
| + return EMPTY_STRING; |
| + } |
| + } |
| + } |
| + |
| + /** |
| + * Get the primitive property with the given name. |
| + * |
| + * @param name |
| + * @return PropertyInfo containing an empty string if property either complex or empty |
| + */ |
| + public Object getPrimitiveProperty(final String namespace,final String name){ |
| + Integer index = propertyIndex(namespace,name); |
| + if (index != null){ |
| + PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| + return propertyInfo.getValue(); |
| + } else { |
| + propertyInfo = new PropertyInfo(); |
| + propertyInfo.setType(String.class); |
| + propertyInfo.setValue(EMPTY_STRING); |
| + propertyInfo.setName(name); |
| + propertyInfo.setNamespace(namespace); |
| + return (Object) propertyInfo.getValue(); |
| + } |
| + } else { |
| + throw new RuntimeException("illegal property: " + name); |
| + } |
| + } |
| + |
| + /** |
| + * Get the toString value of the primitive property with the given name. |
| + * Returns empty string if property either complex or empty |
| + * |
| + * @param name |
| + * @return the string value of the property |
| + */ |
| + public String getPrimitivePropertyAsString(final String namespace,final String name){ |
| + Integer index = propertyIndex(namespace,name); |
| + if (index != null){ |
| + PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| + return propertyInfo.getValue().toString(); |
| + } else { |
| + return EMPTY_STRING; |
| + } |
| + } else { |
| + throw new RuntimeException("illegal property: " + name); |
| + } |
| + } |
| + |
| + /** |
| + * Get the toString value of a primitive property without chance of throwing an |
| + * exception |
| + * |
| + * @param name |
| + * @return the string value of the property if it exists and is primitive; if not, #EMPTY_STRING is |
| + * returned |
| + */ |
| + public Object getPrimitivePropertySafely(final String namespace,final String name) { |
| + Integer index = propertyIndex(namespace,name); |
| + if (index != null){ |
| + PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| + return propertyInfo.getValue().toString(); |
| + } else { |
| + propertyInfo = new PropertyInfo(); |
| + propertyInfo.setType(String.class); |
| + propertyInfo.setValue(EMPTY_STRING); |
| + propertyInfo.setName(name); |
| + propertyInfo.setNamespace(namespace); |
| + return (Object) propertyInfo.getValue(); |
| + } |
| + } else { |
| + return new NullSoapObject(); |
| + } |
| + } |
| + |
| + /** |
| + * Get the toString value of a primitive property without chance of throwing an |
| + * exception |
| + * |
| + * @param name |
| + * @return the string value of the property if it exists and is primitive; if not, #EMPTY_STRING is |
| + * returned |
| + */ |
| + public String getPrimitivePropertySafelyAsString(final String namespace,final String name) { |
| + Integer index = propertyIndex(namespace,name); |
| + if (index != null){ |
| + PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| + return propertyInfo.getValue().toString(); |
| + } else { |
| + return EMPTY_STRING; |
| + } |
| + } else { |
| + return EMPTY_STRING; |
| + } |
| + } |
| + |
| + /** |
| + * Knows whether the given property exists |
| + */ |
| + public boolean hasProperty(final String namespace,final String name) { |
| + if (propertyIndex(namespace,name) != null) { |
| + return true; |
| + } else { |
| + return false; |
| + } |
| + } |
| + |
| + /** |
| + * Get the toString value of the property. |
| + * |
| + * @param namespace |
| + * @param name |
| + * @return |
| + */ |
| + |
| + public String getPropertyAsString(String namespace,String name) { |
| + Integer index = propertyIndex(namespace,name); |
| + if (index != null) { |
| + return getProperty(index.intValue()).toString(); |
| + } else { |
| + throw new RuntimeException("illegal property: " + name); |
| + } |
| + } |
| + |
| /** |
| * Get the toString value of the property. |
| * |
| @@ -301,9 +527,9 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| */ |
| public Object getPrimitiveProperty(final String name) { |
| Integer index = propertyIndex(name); |
| - if (index != null) { |
| + if (index != null){ |
| PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| - if (propertyInfo.getType() != SoapObject.class) { |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| return propertyInfo.getValue(); |
| } else { |
| propertyInfo = new PropertyInfo(); |
| @@ -326,9 +552,9 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| */ |
| public String getPrimitivePropertyAsString(final String name) { |
| Integer index = propertyIndex(name); |
| - if (index != null) { |
| + if (index != null){ |
| PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| - if (propertyInfo.getType() != SoapObject.class) { |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| return propertyInfo.getValue().toString(); |
| } else { |
| return EMPTY_STRING; |
| @@ -348,9 +574,9 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| */ |
| public Object getPrimitivePropertySafely(final String name) { |
| Integer index = propertyIndex(name); |
| - if (index != null) { |
| + if (index != null){ |
| PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| - if (propertyInfo.getType() != SoapObject.class) { |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| return propertyInfo.getValue().toString(); |
| } else { |
| propertyInfo = new PropertyInfo(); |
| @@ -374,9 +600,9 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| */ |
| public String getPrimitivePropertySafelyAsString(final String name) { |
| Integer index = propertyIndex(name); |
| - if (index != null) { |
| + if (index != null){ |
| PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index.intValue()); |
| - if (propertyInfo.getType() != SoapObject.class) { |
| + if (propertyInfo.getType()!=SoapObject.class && propertyInfo.getValue()!=null){ |
| return propertyInfo.getValue().toString(); |
| } else { |
| return EMPTY_STRING; |
| @@ -397,6 +623,18 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| return null; |
| } |
| |
| + |
| + private Integer propertyIndex(String namespace,String name) { |
| + if (name != null && namespace!=null) { |
| + for (int i = 0; i < properties.size(); i++) { |
| + PropertyInfo info= (PropertyInfo) properties.elementAt(i); |
| + if (name.equals(info.getName()) && namespace.equals(info.getNamespace())) { |
| + return new Integer(i); |
| + } |
| + } |
| + } |
| + return null; |
| + } |
| /** |
| * Returns the number of properties |
| * |
| @@ -453,6 +691,17 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| } |
| } |
| |
| + public PropertyInfo getPropertyInfo(int index) { |
| + Object element = properties.elementAt(index); |
| + if (element instanceof PropertyInfo) { |
| + PropertyInfo p = (PropertyInfo) element; |
| + return p; |
| + } else { |
| + // SoapObject |
| + return null; |
| + } |
| + } |
| + |
| /** |
| * Creates a new SoapObject based on this, allows usage of SoapObjects as |
| * templates. One application is to set the expected return type of a soap |
| @@ -466,17 +715,17 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| Object prop = properties.elementAt(propIndex); |
| if (prop instanceof PropertyInfo) { |
| PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(propIndex); |
| - PropertyInfo propertyInfoClonned = (PropertyInfo) propertyInfo.clone(); |
| - o.addProperty(propertyInfoClonned); |
| - } else if (prop instanceof SoapObject) { |
| - o.addSoapObject(((SoapObject) prop).newInstance()); |
| + PropertyInfo propertyInfoClonned = (PropertyInfo)propertyInfo.clone(); |
| + o.addProperty( propertyInfoClonned ); |
| + } else if(prop instanceof SoapObject) { |
| + o.addSoapObject(((SoapObject)prop).newInstance()); |
| } |
| } |
| for (int attribIndex = 0; attribIndex < getAttributeCount(); attribIndex++) { |
| AttributeInfo newAI = new AttributeInfo(); |
| getAttributeInfo(attribIndex, newAI); |
| AttributeInfo attributeInfo = newAI; // (AttributeInfo) |
| - // attributes.elementAt(attribIndex); |
| + // attributes.elementAt(attribIndex); |
| o.addAttribute(attributeInfo); |
| } |
| return o; |
| @@ -513,11 +762,49 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| propertyInfo.type = value == null ? PropertyInfo.OBJECT_CLASS : value |
| .getClass(); |
| propertyInfo.value = value; |
| + return addProperty(propertyInfo); |
| + } |
| + |
| + /** |
| + * Adds a property (parameter) to the object. This is essentially a sub |
| + * element. |
| + * |
| + * @param namespace |
| + * The namespace of the property |
| + * @param name |
| + * The name of the property |
| + * @param value |
| + * the value of the property |
| + */ |
| + public SoapObject addProperty(String namespace,String name, Object value) { |
| + PropertyInfo propertyInfo = new PropertyInfo(); |
| + propertyInfo.name = name; |
| propertyInfo.namespace = namespace; |
| - ///M: HS20 modify by Jungo |
| + propertyInfo.type = value == null ? PropertyInfo.OBJECT_CLASS : value |
| + .getClass(); |
| + propertyInfo.value = value; |
| return addProperty(propertyInfo); |
| } |
| |
| + /** |
| + * Add a property only if the value is not null. |
| + * |
| + * @param namespace |
| + * The namespace of the property |
| + * @param name |
| + * The name of the property |
| + * @param value |
| + * the value of the property |
| + * @return |
| + */ |
| + public SoapObject addPropertyIfValue(String namespace,String name, Object value) { |
| + if (value != null) { |
| + return addProperty(namespace,name, value); |
| + } else { |
| + return this; |
| + } |
| + } |
| + |
| /** |
| * Add a property only if the value is not null. |
| * |
| @@ -597,12 +884,12 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| StringBuffer buf = new StringBuffer(EMPTY_STRING + name + "{"); |
| for (int i = 0; i < getPropertyCount(); i++) { |
| Object prop = properties.elementAt(i); |
| - if (prop instanceof PropertyInfo) { |
| + if(prop instanceof PropertyInfo) { |
| buf.append(EMPTY_STRING) |
| - .append(((PropertyInfo) prop).getName()) |
| - .append("=") |
| - .append(getProperty(i)) |
| - .append("; "); |
| + .append(((PropertyInfo) prop).getName()) |
| + .append("=") |
| + .append(getProperty(i)) |
| + .append("; "); |
| } else { |
| buf.append(((SoapObject) prop).toString()); |
| } |
| @@ -610,4 +897,17 @@ public class SoapObject extends AttributeContainer implements KvmSerializable { |
| buf.append("}"); |
| return buf.toString(); |
| } |
| + public Object getInnerText() { |
| + return innerText; |
| + } |
| + |
| + public void setInnerText(Object innerText) |
| + { |
| + this.innerText=innerText; |
| + } |
| + |
| + public void removePropertyInfo(Object info) |
| + { |
| + properties.remove(info); |
| + } |
| } |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapPrimitive.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapPrimitive.java |
| index d09f7a7..32fe333 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapPrimitive.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapPrimitive.java |
| @@ -34,11 +34,14 @@ package org.ksoap2.serialization; |
| */ |
| |
| public class SoapPrimitive extends AttributeContainer { |
| - String namespace; |
| - String name; |
| - String value; |
| + protected String namespace; |
| + protected String name; |
| + protected Object value; |
| |
| - public SoapPrimitive(String namespace, String name, String value) { |
| + public static final Object NullSkip = new Object(); |
| + public static final Object NullNilElement = new Object(); |
| + |
| + public SoapPrimitive(String namespace, String name, Object value) { |
| this.namespace = namespace; |
| this.name = name; |
| this.value = value; |
| @@ -50,7 +53,7 @@ public class SoapPrimitive extends AttributeContainer { |
| } |
| SoapPrimitive p = (SoapPrimitive) o; |
| boolean varsEqual = name.equals(p.name) |
| - && (namespace == null ? p.namespace == null : namespace.equals(p.namespace)) |
| + && (namespace == null ? p.namespace == null:namespace.equals(p.namespace)) |
| && (value == null ? (p.value == null) : value.equals(p.value)); |
| return varsEqual && attributesAreEqual(p); |
| } |
| @@ -60,7 +63,7 @@ public class SoapPrimitive extends AttributeContainer { |
| } |
| |
| public String toString() { |
| - return value; |
| + return value != null ? value.toString() : null; |
| } |
| |
| public String getNamespace() { |
| @@ -70,4 +73,9 @@ public class SoapPrimitive extends AttributeContainer { |
| public String getName() { |
| return name; |
| } |
| + |
| + public Object getValue() { |
| + return value; |
| + } |
| + |
| } |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapSerializationEnvelope.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapSerializationEnvelope.java |
| index dae09d2..ceeb3f4 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapSerializationEnvelope.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapSerializationEnvelope.java |
| @@ -27,9 +27,9 @@ import org.xmlpull.v1.XmlPullParserException; |
| import org.xmlpull.v1.XmlSerializer; |
| |
| import java.io.IOException; |
| +import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.Vector; |
| -import java.io.ByteArrayOutputStream; |
| |
| import org.kxml2.io.*; |
| |
| @@ -43,29 +43,29 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| protected static final int QNAME_TYPE = 1; |
| protected static final int QNAME_NAMESPACE = 0; |
| protected static final int QNAME_MARSHAL = 3; |
| + protected static final String NULL_LABEL = "null"; |
| + protected static final String NIL_LABEL = "nil"; |
| + static final Marshal DEFAULT_MARSHAL = new DM(); |
| private static final String ANY_TYPE_LABEL = "anyType"; |
| private static final String ARRAY_MAPPING_NAME = "Array"; |
| - private static final String NULL_LABEL = "null"; |
| - private static final String NIL_LABEL = "nil"; |
| private static final String HREF_LABEL = "href"; |
| private static final String ID_LABEL = "id"; |
| private static final String ROOT_LABEL = "root"; |
| private static final String TYPE_LABEL = "type"; |
| private static final String ITEM_LABEL = "item"; |
| private static final String ARRAY_TYPE_LABEL = "arrayType"; |
| - static final Marshal DEFAULT_MARSHAL = new DM(); |
| public Hashtable properties = new Hashtable(); |
| - |
| - Hashtable idMap = new Hashtable(); |
| - Vector multiRef; // = new Vector(); |
| - |
| /** |
| * Set this variable to true if you don't want that type definitions for complex types/objects |
| * are automatically generated (with type "anyType") in the XML-Request, if you don't call the |
| * Method addMapping. This is needed by some Servers which have problems with these type-definitions. |
| */ |
| public boolean implicitTypes; |
| - |
| + /** |
| + * If set to true then all properties with null value will be skipped from the soap message. |
| + * If false then null properties will be sent as <element nil="true" /> |
| + */ |
| + public boolean skipNullProperties; |
| /** |
| * Set this variable to true for compatibility with what seems to be the default encoding for |
| * .Net-Services. This feature is an extremely ugly hack. A much better option is to change the |
| @@ -96,9 +96,10 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| * Set to true to add and ID and ROOT label to the envelope. Change to false for compatibility with WSDL. |
| */ |
| protected boolean addAdornments = true; |
| + Hashtable idMap = new Hashtable(); |
| + Vector multiRef; // = new Vector(); |
| |
| - public SoapSerializationEnvelope(int version) |
| - { |
| + public SoapSerializationEnvelope(int version) { |
| super(version); |
| addMapping(enc, ARRAY_MAPPING_NAME, PropertyInfo.VECTOR_CLASS); |
| DEFAULT_MARSHAL.register(this); |
| @@ -107,23 +108,21 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| /** |
| * @return the addAdornments |
| */ |
| - public boolean isAddAdornments() |
| - { |
| + public boolean isAddAdornments() { |
| return addAdornments; |
| } |
| |
| /** |
| - * @param addAdornments |
| - * the addAdornments to set |
| + * @param addAdornments the addAdornments to set |
| */ |
| - public void setAddAdornments(boolean addAdornments) |
| - { |
| + public void setAddAdornments(boolean addAdornments) { |
| this.addAdornments = addAdornments; |
| } |
| |
| /** |
| * Set the bodyOut to be empty so that no un-needed xml is create. The null value for bodyOut will |
| * cause #writeBody to skip writing anything redundant. |
| + * |
| * @param emptyBody |
| * @see "http://code.google.com/p/ksoap2-android/issues/detail?id=77" |
| */ |
| @@ -133,8 +132,7 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| } |
| } |
| |
| - public void parseBody(XmlPullParser parser) throws IOException, XmlPullParserException |
| - { |
| + public void parseBody(XmlPullParser parser) throws IOException, XmlPullParserException { |
| bodyIn = null; |
| parser.nextTag(); |
| if (parser.getEventType() == XmlPullParser.START_TAG && parser.getNamespace().equals(env) |
| @@ -161,10 +159,11 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| } |
| } |
| |
| - /** Read a SoapObject. This extracts any attributes and then reads the object as a KvmSerializable. */ |
| + /** |
| + * Read a SoapObject. This extracts any attributes and then reads the object as a KvmSerializable. |
| + */ |
| protected void readSerializable(XmlPullParser parser, SoapObject obj) throws IOException, |
| - XmlPullParserException |
| - { |
| + XmlPullParserException { |
| for (int counter = 0; counter < parser.getAttributeCount(); counter++) { |
| String attributeName = parser.getAttributeName(counter); |
| String value = parser.getAttributeValue(counter); |
| @@ -173,11 +172,21 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| readSerializable(parser, (KvmSerializable) obj); |
| } |
| |
| - /** Read a KvmSerializable. */ |
| + /** |
| + * Read a KvmSerializable. |
| + */ |
| protected void readSerializable(XmlPullParser parser, KvmSerializable obj) throws IOException, |
| - XmlPullParserException |
| - { |
| - while (parser.nextTag() != XmlPullParser.END_TAG) { |
| + XmlPullParserException { |
| + int tag = 0; |
| + try { |
| + tag = parser.nextTag(); |
| + } catch (XmlPullParserException e) { |
| + if(obj instanceof HasInnerText){ |
| + ((HasInnerText)obj).setInnerText((parser.getText() != null) ? parser.getText() : ""); |
| + } |
| + tag = parser.nextTag(); |
| + } |
| + while (tag != XmlPullParser.END_TAG) { |
| String name = parser.getName(); |
| if (!implicitTypes || !(obj instanceof SoapObject)) { |
| PropertyInfo info = new PropertyInfo(); |
| @@ -188,8 +197,7 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| info.clear(); |
| obj.getPropertyInfo(i, properties, info); |
| |
| - if ((name.equals(info.name) && info.namespace == null) |
| - || |
| + if ((name.equals(info.name) && info.namespace == null) || |
| (name.equals(info.name) && parser.getNamespace().equals(info.namespace))) { |
| propertyFound = true; |
| obj.setProperty(i, read(parser, obj, i, null, null, info)); |
| @@ -199,21 +207,42 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| if (!propertyFound) { |
| if (avoidExceptionForUnknownProperty) { |
| // Dummy loop to read until corresponding END tag |
| - while (parser.next() != XmlPullParser.END_TAG |
| - || !name.equals(parser.getName())) { |
| + while (parser.next() != XmlPullParser.END_TAG || !name.equals(parser.getName())) { |
| } |
| ; |
| } else { |
| throw new RuntimeException("Unknown Property: " + name); |
| } |
| + } else { |
| + if (obj instanceof HasAttributes) { |
| + HasAttributes soapObject = (HasAttributes) obj; |
| + int cnt = parser.getAttributeCount(); |
| + for (int counter = 0; counter < cnt; counter++) { |
| + AttributeInfo attributeInfo = new AttributeInfo(); |
| + attributeInfo.setName(parser.getAttributeName(counter)); |
| + attributeInfo.setValue(parser.getAttributeValue(counter)); |
| + attributeInfo.setNamespace(parser.getAttributeNamespace(counter)); |
| + attributeInfo.setType(parser.getAttributeType(counter)); |
| + soapObject.setAttribute(attributeInfo); |
| + |
| + } |
| + } |
| } |
| } else { |
| // I can only make this work for SoapObjects - hence the check above |
| // I don't understand namespaces well enough to know whether it is correct in the next line... |
| - ((SoapObject) obj).addProperty(parser.getName(), |
| - read(parser, obj, obj.getPropertyCount(), |
| - ((SoapObject) obj).getNamespace(), name, PropertyInfo.OBJECT_TYPE)); |
| + ((SoapObject) obj).addProperty(parser.getName(), read(parser, obj, obj.getPropertyCount(), |
| + ((SoapObject) obj).getNamespace(), name, PropertyInfo.OBJECT_TYPE)); |
| + } |
| + try { |
| + tag = parser.nextTag(); |
| + } catch (XmlPullParserException e) { |
| + if(obj instanceof HasInnerText){ |
| + ((HasInnerText)obj).setInnerText((parser.getText() != null) ? parser.getText() : ""); |
| + } |
| + tag = parser.nextTag(); |
| } |
| + |
| } |
| parser.require(XmlPullParser.END_TAG, null, null); |
| } |
| @@ -278,9 +307,8 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| } |
| |
| while (parser.getEventType() != XmlPullParser.END_TAG) { |
| - so.addProperty(parser.getName(), |
| - read(parser, so, so.getPropertyCount(), null, null, |
| - PropertyInfo.OBJECT_TYPE)); |
| + so.addProperty(parser.getNamespace(),parser.getName(), read(parser, so, so.getPropertyCount(), |
| + null, null, PropertyInfo.OBJECT_TYPE)); |
| parser.nextTag(); |
| } |
| result = so; |
| @@ -293,12 +321,15 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| if (value == null) { |
| return dflt; |
| } |
| - return value.length() - start < 3 ? dflt : Integer.parseInt(value.substring(start + 1, |
| - value.length() - 1)); |
| + try { |
| + return value.length() - start < 3 ? dflt : Integer.parseInt(value.substring(start + 1, |
| + value.length() - 1)); |
| + } catch (Exception ex) { |
| + return dflt; |
| + } |
| } |
| |
| - protected void readVector(XmlPullParser parser, Vector v, PropertyInfo elementType) |
| - throws IOException, |
| + protected void readVector(XmlPullParser parser, Vector v, PropertyInfo elementType) throws IOException, |
| XmlPullParserException { |
| String namespace = null; |
| String name = null; |
| @@ -337,14 +368,23 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| parser.require(XmlPullParser.END_TAG, null, null); |
| } |
| |
| + /** |
| + * This method returns id from the href attribute value. |
| + * By default we assume that href value looks like this: #id so we basically have to remove the first character. |
| + * But in theory there could be a different value format, like cid:value, etc... |
| + */ |
| + protected String getIdFromHref(String hrefValue) { |
| + return hrefValue.substring(1); |
| + } |
| + |
| /** |
| * Builds an object from the XML stream. This method is public for usage in conjuction with Marshal |
| * subclasses. Precondition: On the start tag of the object or property, so href can be read. |
| */ |
| |
| - public Object read(XmlPullParser parser, Object owner, int index, String namespace, |
| - String name, |
| - PropertyInfo expected) throws IOException, XmlPullParserException { |
| + public Object read(XmlPullParser parser, Object owner, int index, String namespace, String name, |
| + PropertyInfo expected) |
| + throws IOException, XmlPullParserException { |
| String elementName = parser.getName(); |
| String href = parser.getAttributeValue(null, HREF_LABEL); |
| Object obj; |
| @@ -352,7 +392,7 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| if (owner == null) { |
| throw new RuntimeException("href at root level?!?"); |
| } |
| - href = href.substring(1); |
| + href = getIdFromHref(href); |
| obj = idMap.get(href); |
| if (obj == null || obj instanceof FwdRef) { |
| FwdRef f = new FwdRef(); |
| @@ -402,21 +442,8 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| } |
| // finally, care about the id.... |
| if (id != null) { |
| - Object hlp = idMap.get(id); |
| - if (hlp instanceof FwdRef) { |
| - FwdRef f = (FwdRef) hlp; |
| - do { |
| - if (f.obj instanceof KvmSerializable) { |
| - ((KvmSerializable) f.obj).setProperty(f.index, obj); |
| - } else { |
| - ((Vector) f.obj).setElementAt(obj, f.index); |
| - } |
| - f = f.next; |
| - } while (f != null); |
| - } else if (hlp != null) { |
| - throw new RuntimeException("double ID"); |
| - } |
| - idMap.put(id, obj); |
| + resolveReference(id, obj); |
| + |
| } |
| } |
| |
| @@ -424,12 +451,30 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| return obj; |
| } |
| |
| + protected void resolveReference(String id, Object obj) { |
| + Object hlp = idMap.get(id); |
| + if (hlp instanceof FwdRef) { |
| + FwdRef f = (FwdRef) hlp; |
| + do { |
| + if (f.obj instanceof KvmSerializable) { |
| + ((KvmSerializable) f.obj).setProperty(f.index, obj); |
| + } else { |
| + ((Vector) f.obj).setElementAt(obj, f.index); |
| + } |
| + f = f.next; |
| + } |
| + while (f != null); |
| + } else if (hlp != null) { |
| + throw new RuntimeException("double ID"); |
| + } |
| + idMap.put(id, obj); |
| + } |
| + |
| /** |
| * Returns a new object read from the given parser. If no mapping is found, null is returned. This method |
| * is used by the SoapParser in order to convert the XML code to Java objects. |
| */ |
| - public Object readInstance(XmlPullParser parser, String namespace, String name, |
| - PropertyInfo expected) |
| + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) |
| throws IOException, XmlPullParserException { |
| Object obj = qNameToClass.get(new SoapPrimitive(namespace, name, null)); |
| if (obj == null) { |
| @@ -448,10 +493,30 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| throw new RuntimeException(e.toString()); |
| } |
| } |
| + if (obj instanceof HasAttributes) { |
| + HasAttributes soapObject = (HasAttributes) obj; |
| + int cnt = parser.getAttributeCount(); |
| + for (int counter = 0; counter < cnt; counter++) { |
| + |
| + AttributeInfo attributeInfo = new AttributeInfo(); |
| + attributeInfo.setName(parser.getAttributeName(counter)); |
| + attributeInfo.setValue(parser.getAttributeValue(counter)); |
| + attributeInfo.setNamespace(parser.getAttributeNamespace(counter)); |
| + attributeInfo.setType(parser.getAttributeType(counter)); |
| + |
| + soapObject.setAttribute(attributeInfo); |
| + |
| + } |
| + } |
| + |
| // ok, obj is now the instance, fill it.... |
| if (obj instanceof SoapObject) { |
| readSerializable(parser, (SoapObject) obj); |
| } else if (obj instanceof KvmSerializable) { |
| + |
| + if(obj instanceof HasInnerText){ |
| + ((HasInnerText)obj).setInnerText((parser.getText() != null) ? parser.getText() : ""); |
| + } |
| readSerializable(parser, (KvmSerializable) obj); |
| } else if (obj instanceof Vector) { |
| readVector(parser, (Vector) obj, expected.elementType); |
| @@ -476,15 +541,11 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| } |
| if (type instanceof SoapObject) { |
| SoapObject so = (SoapObject) type; |
| - return new Object[] { |
| - so.getNamespace(), so.getName(), null, null |
| - }; |
| + return new Object[]{so.getNamespace(), so.getName(), null, null}; |
| } |
| if (type instanceof SoapPrimitive) { |
| SoapPrimitive sp = (SoapPrimitive) type; |
| - return new Object[] { |
| - sp.getNamespace(), sp.getName(), null, DEFAULT_MARSHAL |
| - }; |
| + return new Object[]{sp.getNamespace(), sp.getName(), null, DEFAULT_MARSHAL}; |
| } |
| if ((type instanceof Class) && type != PropertyInfo.OBJECT_CLASS) { |
| Object[] tmp = (Object[]) classToQName.get(((Class) type).getName()); |
| @@ -492,9 +553,7 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| return tmp; |
| } |
| } |
| - return new Object[] { |
| - xsd, ANY_TYPE_LABEL, null, null |
| - }; |
| + return new Object[]{xsd, ANY_TYPE_LABEL, null, null}; |
| } |
| |
| /** |
| @@ -503,11 +562,8 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| */ |
| public void addMapping(String namespace, String name, Class clazz, Marshal marshal) { |
| qNameToClass |
| - .put(new SoapPrimitive(namespace, name, null), marshal == null ? (Object) clazz |
| - : marshal); |
| - classToQName.put(clazz.getName(), new Object[] { |
| - namespace, name, null, marshal |
| - }); |
| + .put(new SoapPrimitive(namespace, name, null), marshal == null ? (Object) clazz : marshal); |
| + classToQName.put(clazz.getName(), new Object[]{namespace, name, null, marshal}); |
| } |
| |
| /** |
| @@ -528,11 +584,14 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| /** |
| * Response from the soap call. Pulls the object from the wrapper object and returns it. |
| * |
| - * @since 2.0.3 |
| * @return response from the soap call. |
| * @throws SoapFault |
| + * @since 2.0.3 |
| */ |
| public Object getResponse() throws SoapFault { |
| + if (bodyIn == null) { |
| + return null; |
| + } |
| if (bodyIn instanceof SoapFault) { |
| throw (SoapFault) bodyIn; |
| } |
| @@ -554,8 +613,7 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| /** |
| * Serializes the request object to the given XmlSerliazer object |
| * |
| - * @param writer |
| - * XmlSerializer object to write the body into. |
| + * @param writer XmlSerializer object to write the body into. |
| */ |
| public void writeBody(XmlSerializer writer) throws IOException { |
| // allow an empty body without any tags in it |
| @@ -564,36 +622,48 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| multiRef = new Vector(); |
| multiRef.addElement(bodyOut); |
| Object[] qName = getInfo(null, bodyOut); |
| - writer.startTag((dotNet) ? "" : (String) qName[QNAME_NAMESPACE], |
| - (String) qName[QNAME_TYPE]); //<spp:sppPostDevData |
| - if (dotNet) { |
| - writer.attribute(null, "xmlns", (String) qName[QNAME_NAMESPACE]); |
| - } |
| + |
| + writer.startTag((dotNet) ? "" : (String) qName[QNAME_NAMESPACE], (String) qName[QNAME_TYPE]); |
| + |
| + if (dotNet) { |
| + writer.attribute(null, "xmlns", (String) qName[QNAME_NAMESPACE]); |
| + } |
| + |
| if (addAdornments) { |
| writer.attribute(null, ID_LABEL, qName[2] == null ? ("o" + 0) : (String) qName[2]); |
| writer.attribute(enc, ROOT_LABEL, "1"); |
| } |
| - writeElement(writer, bodyOut, null, qName[QNAME_MARSHAL]); //.... |
| - writer.endTag((dotNet) ? "" : (String) qName[QNAME_NAMESPACE], |
| - (String) qName[QNAME_TYPE]);//</spp:sppPostDevData> |
| + writeElement(writer, bodyOut, null, qName[QNAME_MARSHAL]); |
| + writer.endTag((dotNet) ? "" : (String) qName[QNAME_NAMESPACE], (String) qName[QNAME_TYPE]); |
| } |
| } |
| |
| - /** |
| - * Writes the body of an SoapObject. This method write the attributes and then calls |
| - * "writeObjectBody (writer, (KvmSerializable)obj);" |
| - */ |
| - public void writeObjectBody(XmlSerializer writer, SoapObject obj) throws IOException { |
| - SoapObject soapObject = (SoapObject) obj; |
| + private void writeAttributes(XmlSerializer writer, HasAttributes obj) throws IOException { |
| + HasAttributes soapObject = (HasAttributes) obj; |
| int cnt = soapObject.getAttributeCount(); |
| for (int counter = 0; counter < cnt; counter++) { |
| AttributeInfo attributeInfo = new AttributeInfo(); |
| soapObject.getAttributeInfo(counter, attributeInfo); |
| - writer.attribute(attributeInfo.getNamespace(), attributeInfo.getName(), attributeInfo |
| - .getValue() |
| - .toString()); |
| + soapObject.getAttribute(counter, attributeInfo); |
| + if (attributeInfo.getValue() != null) { |
| + writer.attribute(attributeInfo.getNamespace(), attributeInfo.getName(), |
| + attributeInfo.getValue().toString()); |
| + } |
| + } |
| + } |
| + |
| + public void writeArrayListBodyWithAttributes(XmlSerializer writer, KvmSerializable obj) throws IOException { |
| + if (obj instanceof HasAttributes) { |
| + writeAttributes(writer, (HasAttributes) obj); |
| } |
| - writeObjectBody(writer, (KvmSerializable) obj); |
| + writeArrayListBody(writer, (ArrayList) obj); |
| + } |
| + |
| + public void writeObjectBodyWithAttributes(XmlSerializer writer, KvmSerializable obj) throws IOException { |
| + if (obj instanceof HasAttributes) { |
| + writeAttributes(writer, (HasAttributes) obj); |
| + } |
| + writeObjectBody(writer, obj); |
| } |
| |
| /** |
| @@ -614,9 +684,12 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| if (!(prop instanceof SoapObject)) { |
| // prop is a PropertyInfo |
| if ((propertyInfo.flags & PropertyInfo.TRANSIENT) == 0) { |
| - writer.startTag(propertyInfo.namespace, propertyInfo.name); |
| - writeProperty(writer, obj.getProperty(i), propertyInfo); |
| - writer.endTag(propertyInfo.namespace, propertyInfo.name); |
| + Object objValue = obj.getProperty(i); |
| + if ((prop != null || !skipNullProperties) && (objValue != SoapPrimitive.NullSkip)) { |
| + writer.startTag(propertyInfo.namespace, propertyInfo.name); |
| + writeProperty(writer, objValue, propertyInfo); |
| + writer.endTag(propertyInfo.namespace, propertyInfo.name); |
| + } |
| } |
| } else { |
| // prop is a SoapObject |
| @@ -633,46 +706,47 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| name = (String) qName[QNAME_TYPE]; |
| } |
| |
| - // treat MO data as CDATA |
| - if (name.equals("DevInfo") || name.equals("DevDetail") |
| - || name.equals("PerProviderSubscription") || // format v4 |
| - name.equals("MgmtTree") // format v6 |
| - ) { |
| - ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| - XmlSerializer xw = new KXmlSerializer(); |
| - xw.setOutput(bos, "UTF-8"); |
| - xw.startTag((dotNet) ? "" : namespace, name); |
| - if (!implicitTypes) { |
| - String prefix = writer.getPrefix(namespace, true); |
| - writer.attribute(xsi, TYPE_LABEL, prefix + ":" + type); |
| - } |
| - writeObjectBody(xw, nestedSoap); |
| - xw.endTag((dotNet) ? "" : namespace, name); |
| - xw.flush(); |
| - //bos.write('\r'); |
| - //bos.write('\n'); |
| - bos.flush(); |
| - writer.cdsect(bos.toString()); |
| + // prefer the namespace from the property info |
| + if (propertyInfo.namespace != null && propertyInfo.namespace.length() > 0) { |
| + namespace = propertyInfo.namespace; |
| + } else { |
| + namespace = (String) qName[QNAME_NAMESPACE]; |
| + } |
| + |
| + writer.startTag(namespace, name); |
| + if (!implicitTypes) { |
| + String prefix = writer.getPrefix(namespace, true); |
| + writer.attribute(xsi, TYPE_LABEL, prefix + ":" + type); |
| + } |
| + writeObjectBodyWithAttributes(writer, nestedSoap); |
| + writer.endTag(namespace, name); |
| + } |
| + } |
| + writeInnerText(writer, obj); |
| + |
| + } |
| + |
| + private void writeInnerText(XmlSerializer writer, KvmSerializable obj) throws IOException { |
| + if(obj instanceof HasInnerText){ |
| + |
| + Object value=((HasInnerText)obj).getInnerText(); |
| + if (value != null) { |
| + if(value instanceof ValueWriter) |
| + { |
| + ((ValueWriter)value).write(writer); |
| } |
| else |
| { |
| - writer.startTag((dotNet) ? "" : namespace, name); |
| - if (!implicitTypes) { |
| - String prefix = writer.getPrefix(namespace, true); |
| - writer.attribute(xsi, TYPE_LABEL, prefix + ":" + type); |
| - } |
| - writeObjectBody(writer, nestedSoap); |
| - writer.endTag((dotNet) ? "" : namespace, name); |
| + writer.cdsect(value.toString()); |
| } |
| + |
| } |
| } |
| } |
| |
| - protected void writeProperty(XmlSerializer writer, Object obj, PropertyInfo type) |
| - throws IOException { |
| - if (obj == null) { |
| - ///M: Modify for HS20 |
| - //writer.attribute(xsi, version >= VER12 ? NIL_LABEL : NULL_LABEL, "true"); |
| + protected void writeProperty(XmlSerializer writer, Object obj, PropertyInfo type) throws IOException { |
| + if (obj == null || obj == SoapPrimitive.NullNilElement) { |
| + writer.attribute(xsi, version >= VER12 ? NIL_LABEL : NULL_LABEL, "true"); |
| return; |
| } |
| Object[] qName = getInfo(null, obj); |
| @@ -692,15 +766,19 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| } |
| } |
| |
| - private void writeElement(XmlSerializer writer, Object element, PropertyInfo type, |
| - Object marshal) |
| + protected void writeElement(XmlSerializer writer, Object element, PropertyInfo type, Object marshal) |
| throws IOException { |
| if (marshal != null) { |
| ((Marshal) marshal).writeInstance(writer, element); |
| - } else if (element instanceof SoapObject) { |
| - writeObjectBody(writer, (SoapObject) element); |
| - } else if (element instanceof KvmSerializable) { |
| - writeObjectBody(writer, (KvmSerializable) element); |
| + } else if (element instanceof KvmSerializable || element == SoapPrimitive.NullNilElement |
| + || element == SoapPrimitive.NullSkip) { |
| + if (element instanceof ArrayList) { |
| + writeArrayListBodyWithAttributes(writer, (KvmSerializable) element); |
| + } else { |
| + writeObjectBodyWithAttributes(writer, (KvmSerializable) element); |
| + } |
| + } else if (element instanceof HasAttributes) { |
| + writeAttributes(writer, (HasAttributes) element); |
| } else if (element instanceof Vector) { |
| writeVectorBody(writer, (Vector) element, type.elementType); |
| } else { |
| @@ -708,6 +786,65 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| } |
| } |
| |
| + protected void writeArrayListBody(XmlSerializer writer, ArrayList list) |
| + throws IOException { |
| + KvmSerializable obj = (KvmSerializable) list; |
| + int cnt = list.size(); |
| + PropertyInfo propertyInfo = new PropertyInfo(); |
| + String namespace; |
| + String name; |
| + String type; |
| + for (int i = 0; i < cnt; i++) { |
| + // get the property |
| + Object prop = obj.getProperty(i); |
| + // and importantly also get the property info which holds the name potentially! |
| + obj.getPropertyInfo(i, properties, propertyInfo); |
| + |
| + if (!(prop instanceof SoapObject)) { |
| + // prop is a PropertyInfo |
| + if ((propertyInfo.flags & PropertyInfo.TRANSIENT) == 0) { |
| + Object objValue = obj.getProperty(i); |
| + if ((prop != null || !skipNullProperties) && (objValue != SoapPrimitive.NullSkip)) { |
| + writer.startTag(propertyInfo.namespace, propertyInfo.name); |
| + writeProperty(writer, objValue, propertyInfo); |
| + writer.endTag(propertyInfo.namespace, propertyInfo.name); |
| + } |
| + } |
| + } else { |
| + |
| + // prop is a SoapObject |
| + SoapObject nestedSoap = (SoapObject) prop; |
| + // lets get the info from the soap object itself |
| + Object[] qName = getInfo(null, nestedSoap); |
| + namespace = (String) qName[QNAME_NAMESPACE]; |
| + type = (String) qName[QNAME_TYPE]; |
| + |
| + // prefer the name from the property info |
| + if (propertyInfo.name != null && propertyInfo.name.length() > 0) { |
| + name = propertyInfo.name; |
| + } else { |
| + name = (String) qName[QNAME_TYPE]; |
| + } |
| + |
| + // prefer the namespace from the property info |
| + if (propertyInfo.namespace != null && propertyInfo.namespace.length() > 0) { |
| + namespace = propertyInfo.namespace; |
| + } else { |
| + namespace = (String) qName[QNAME_NAMESPACE]; |
| + } |
| + |
| + writer.startTag(namespace, name); |
| + if (!implicitTypes) { |
| + String prefix = writer.getPrefix(namespace, true); |
| + writer.attribute(xsi, TYPE_LABEL, prefix + ":" + type); |
| + } |
| + writeObjectBodyWithAttributes(writer, nestedSoap); |
| + writer.endTag(namespace, name); |
| + } |
| + } |
| + writeInnerText(writer, obj); |
| + } |
| + |
| protected void writeVectorBody(XmlSerializer writer, Vector vector, PropertyInfo elementType) |
| throws IOException { |
| String itemsTagName = ITEM_LABEL; |
| @@ -727,9 +864,13 @@ public class SoapSerializationEnvelope extends SoapEnvelope |
| |
| // This removes the arrayType attribute from the xml for arrays(required for most .Net services to work) |
| if (!implicitTypes) { |
| - writer.attribute(enc, ARRAY_TYPE_LABEL, writer.getPrefix((String) arrType[0], false) |
| - + ":" |
| + writer.attribute(enc, ARRAY_TYPE_LABEL, writer.getPrefix((String) arrType[0], false) + ":" |
| + arrType[1] + "[" + cnt + "]"); |
| + } else { |
| + // Get the namespace from mappings if available when arrayType is removed for .Net |
| + if (itemsNamespace == null) { |
| + itemsNamespace = (String) arrType[0]; |
| + } |
| } |
| |
| boolean skipped = false; |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/ValueWriter.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/ValueWriter.java |
| new file mode 100644 |
| index 0000000..fdbaa21 |
| --- /dev/null |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/ValueWriter.java |
| @@ -0,0 +1,13 @@ |
| +package org.ksoap2.serialization; |
| + |
| +import org.xmlpull.v1.XmlSerializer; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Created by robocik on 2015-09-25. |
| + */ |
| +public interface ValueWriter |
| +{ |
| + void write(XmlSerializer writer) throws IOException; |
| +} |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/transport/ServiceConnection.java b/ksoap2-base/src/main/java/org/ksoap2/transport/ServiceConnection.java |
| index 8e14ee7..9dd3837 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/transport/ServiceConnection.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/transport/ServiceConnection.java |
| @@ -21,8 +21,10 @@ |
| |
| package org.ksoap2.transport; |
| |
| +import java.io.IOException; |
| +import java.io.InputStream; |
| +import java.io.OutputStream; |
| import java.util.List; |
| -import java.io.*; |
| |
| /** |
| * Interface to allow the abstraction of the raw transport information |
| @@ -58,6 +60,13 @@ public interface ServiceConnection { |
| */ |
| public List getResponseProperties() throws IOException; |
| |
| + /** |
| + * Returns the numerical HTTP status to the caller |
| + * @return an integer status value |
| + * @throws IOException |
| + */ |
| + public int getResponseCode() throws IOException; |
| + |
| /** |
| * Set properties on the outgoing connection. |
| * |
| @@ -88,6 +97,8 @@ public interface ServiceConnection { |
| **/ |
| public void setFixedLengthStreamingMode(int contentLength); |
| |
| + public void setChunkedStreamingMode(); |
| + |
| /** |
| * Open and return the outputStream to the endpoint. |
| * |
| diff --git a/ksoap2-base/src/main/java/org/ksoap2/transport/Transport.java b/ksoap2-base/src/main/java/org/ksoap2/transport/Transport.java |
| index b2f6587..2f3d523 100644 |
| --- a/ksoap2-base/src/main/java/org/ksoap2/transport/Transport.java |
| +++ b/ksoap2-base/src/main/java/org/ksoap2/transport/Transport.java |
| @@ -23,9 +23,13 @@ |
| |
| package org.ksoap2.transport; |
| |
| +import java.util.HashMap; |
| +import java.util.Iterator; |
| import java.util.List; |
| import java.io.*; |
| +import java.net.MalformedURLException; |
| import java.net.Proxy; |
| +import java.net.URL; |
| |
| import org.ksoap2.*; |
| import org.kxml2.io.*; |
| @@ -40,9 +44,9 @@ import org.xmlpull.v1.*; |
| abstract public class Transport { |
| |
| /** |
| - * Added to enable web service interactions on the emulator |
| - * to be debugged with Fiddler2 (Windows) but provides utility |
| - * for other proxy requirements. |
| + * Added to enable web service interactions on the emulator to be debugged |
| + * with Fiddler2 (Windows) but provides utility for other proxy |
| + * requirements. |
| */ |
| protected Proxy proxy; |
| protected String url; |
| @@ -61,6 +65,12 @@ abstract public class Transport { |
| |
| private int bufferLength = ServiceConnection.DEFAULT_BUFFER_SIZE; |
| |
| + private HashMap prefixes = new HashMap(); |
| + |
| + public HashMap getPrefixes() { |
| + return prefixes; |
| + } |
| + |
| public Transport() { |
| } |
| |
| @@ -82,9 +92,12 @@ abstract public class Transport { |
| /** |
| * Construct the transport object |
| * |
| - * @param proxy Specifies the proxy server to use for |
| - * accessing the web service or <code>null</code> if a direct connection is available |
| - * @param url Specifies the web service url |
| + * @param proxy |
| + * Specifies the proxy server to use for accessing the web |
| + * service or <code>null</code> if a direct connection is |
| + * available |
| + * @param url |
| + * Specifies the web service url |
| * |
| */ |
| public Transport(Proxy proxy, String url) { |
| @@ -114,23 +127,30 @@ abstract public class Transport { |
| xp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); |
| xp.setInput(is, null); |
| envelope.parse(xp); |
| + /* |
| + * Fix memory leak when running on android in strict mode. Issue 133 |
| + */ |
| + is.close(); |
| } |
| |
| /** |
| * Serializes the request. |
| */ |
| - protected byte[] createRequestData(SoapEnvelope envelope, String encoding) throws IOException { |
| - System.out.println("createRequestData"); |
| + protected byte[] createRequestData(SoapEnvelope envelope, String encoding) |
| + throws IOException { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(bufferLength); |
| byte result[] = null; |
| bos.write(xmlVersionTag.getBytes()); |
| - System.out.println("bos.write"); |
| XmlSerializer xw = new KXmlSerializer(); |
| - System.out.println("new KXmlSerializer"); |
| + |
| + final Iterator keysIter = prefixes.keySet().iterator(); |
| + |
| xw.setOutput(bos, encoding); |
| - System.out.println("xw.setOutput"); |
| + while (keysIter.hasNext()) { |
| + String key = (String) keysIter.next(); |
| + xw.setPrefix(key, (String) prefixes.get(key)); |
| + } |
| envelope.write(xw); |
| - System.out.println("envelope.write"); |
| xw.flush(); |
| bos.write('\r'); |
| bos.write('\n'); |
| @@ -138,14 +158,14 @@ abstract public class Transport { |
| result = bos.toByteArray(); |
| xw = null; |
| bos = null; |
| - System.out.println("createRequestData end"); |
| return result; |
| } |
| |
| /** |
| * Serializes the request. |
| */ |
| - protected byte[] createRequestData(SoapEnvelope envelope) throws IOException { |
| + protected byte[] createRequestData(SoapEnvelope envelope) |
| + throws IOException { |
| return createRequestData(envelope, null); |
| } |
| |
| @@ -159,6 +179,12 @@ abstract public class Transport { |
| this.url = url; |
| } |
| |
| + public String getUrl() |
| + { |
| + return url; |
| + } |
| + |
| + |
| /** |
| * Sets the version tag for the outgoing soap call. Example <?xml |
| * version=\"1.0\" encoding=\"UTF-8\"?> |
| @@ -177,57 +203,94 @@ abstract public class Transport { |
| } |
| |
| /** |
| - * Perform a soap call with a given namespace and the given envelope providing |
| - * any extra headers that the user requires such as cookies. Headers that are |
| - * returned by the web service will be returned to the caller in the form of a |
| - * <code>List</code> of <code>HeaderProperty</code> instances. |
| + * Perform a soap call with a given namespace and the given envelope |
| + * providing any extra headers that the user requires such as cookies. |
| + * Headers that are returned by the web service will be returned to the |
| + * caller in the form of a <code>List</code> of <code>HeaderProperty</code> |
| + * instances. |
| + * |
| + * @param soapAction |
| + * the namespace with which to perform the call in. |
| + * @param envelope |
| + * the envelope the contains the information for the call. |
| + * @param headers |
| + * <code>List</code> of <code>HeaderProperty</code> headers to |
| + * send with the SOAP request. |
| + * |
| + * @return Headers returned by the web service as a <code>List</code> of |
| + * <code>HeaderProperty</code> instances. |
| + */ |
| + abstract public List call(String soapAction, SoapEnvelope envelope, |
| + List headers) throws IOException, XmlPullParserException; |
| + |
| + /** |
| + * Perform a soap call with a given namespace and the given envelope |
| + * providing any extra headers that the user requires such as cookies. |
| + * Headers that are returned by the web service will be returned to the |
| + * caller in the form of a <code>List</code> of <code>HeaderProperty</code> |
| + * instances. |
| * |
| - * @param targetNamespace |
| + * @param soapAction |
| * the namespace with which to perform the call in. |
| * @param envelope |
| * the envelope the contains the information for the call. |
| * @param headers |
| - * <code>List</code> of <code>HeaderProperty</code> headers to send with the SOAP request. |
| + * <code>List</code> of <code>HeaderProperty</code> headers to |
| + * send with the SOAP request. |
| + * @param outputFile |
| + * a file to stream the response into rather than parsing it, |
| + * streaming happens when file is not null |
| * |
| * @return Headers returned by the web service as a <code>List</code> of |
| - * <code>HeaderProperty</code> instances. |
| + * <code>HeaderProperty</code> instances. |
| */ |
| - abstract public List call(String targetNamespace, SoapEnvelope envelope, List headers) |
| - throws IOException, XmlPullParserException; |
| + abstract public List call(String soapAction, SoapEnvelope envelope, |
| + List headers, File outputFile) throws IOException, |
| + XmlPullParserException; |
| |
| /** |
| * Perform a soap call with a given namespace and the given envelope. |
| * |
| - * @param targetNamespace |
| + * @param soapAction |
| * the namespace with which to perform the call in. |
| * @param envelope |
| * the envelope the contains the information for the call. |
| */ |
| - public void call(String targetNamespace, SoapEnvelope envelope) throws IOException, |
| - XmlPullParserException { |
| - call(targetNamespace, envelope, null); |
| + public void call(String soapAction, SoapEnvelope envelope) |
| + throws IOException, XmlPullParserException { |
| + call(soapAction, envelope, null); |
| } |
| |
| /** |
| * Return the name of the host that is specified as the web service target |
| - * |
| + * |
| * @return Host name |
| */ |
| - abstract public String getHost(); |
| + public String getHost() throws MalformedURLException { |
| + |
| + return new URL(url).getHost(); |
| + } |
| |
| /** |
| - * Return the port number of the host that is specified as the web service target |
| - * |
| + * Return the port number of the host that is specified as the web service |
| + * target |
| + * |
| * @return Port number |
| */ |
| - abstract public int getPort(); |
| + public int getPort() throws MalformedURLException { |
| + |
| + return new URL(url).getPort(); |
| + } |
| |
| /** |
| * Return the path to the web service target |
| - * |
| + * |
| * @return The URL's path |
| */ |
| - abstract public String getPath(); |
| + public String getPath() throws MalformedURLException { |
| + |
| + return new URL(url).getPath(); |
| + } |
| |
| abstract public ServiceConnection getServiceConnection() throws IOException; |
| } |
| diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/serialization/MarshalFloat.java b/ksoap2-j2se/src/main/java/org/ksoap2/serialization/MarshalFloat.java |
| index 71c8caa..61a5e2c 100644 |
| --- a/ksoap2-j2se/src/main/java/org/ksoap2/serialization/MarshalFloat.java |
| +++ b/ksoap2-j2se/src/main/java/org/ksoap2/serialization/MarshalFloat.java |
| @@ -27,8 +27,7 @@ import org.xmlpull.v1.*; |
| |
| public class MarshalFloat implements Marshal { |
| |
| - public Object readInstance(XmlPullParser parser, String namespace, String name, |
| - PropertyInfo propertyInfo) |
| + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo propertyInfo) |
| throws IOException, XmlPullParserException { |
| String stringValue = parser.nextText(); |
| Object result; |
| diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpResponseException.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpResponseException.java |
| new file mode 100644 |
| index 0000000..f7fb866 |
| --- /dev/null |
| +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpResponseException.java |
| @@ -0,0 +1,60 @@ |
| +package org.ksoap2.transport; |
| + |
| +import java.io.IOException; |
| +import java.util.List; |
| + |
| +/** |
| + * HttpResponseException is an IOException that is to be thrown when a Http response code is different from 200. |
| + * It allows for easier retrieval of the Http response code from the connection. |
| + * |
| + * @author Rui Pereira <[email protected]> |
| + */ |
| +public class HttpResponseException extends IOException { |
| + |
| + private int statusCode; |
| + private List responseHeaders; |
| + |
| + public HttpResponseException(int statusCode) { |
| + super(); |
| + this.statusCode = statusCode; |
| + } |
| + |
| + public HttpResponseException(String detailMessage, int statusCode) { |
| + super(detailMessage); |
| + this.statusCode = statusCode; |
| + } |
| + |
| + public HttpResponseException(String detailMessage, int statusCode,List responseHeaders) { |
| + super(detailMessage); |
| + this.statusCode = statusCode; |
| + this.responseHeaders=responseHeaders; |
| + } |
| + |
| + public HttpResponseException(String message, Throwable cause, int statusCode) { |
| + super(message, cause); |
| + this.statusCode = statusCode; |
| + } |
| + |
| + public HttpResponseException(Throwable cause, int statusCode) { |
| + super(cause); |
| + this.statusCode = statusCode; |
| + } |
| + |
| + /** |
| + * Returns the unexpected Http response code |
| + * |
| + * @return response code |
| + */ |
| + public int getStatusCode() { |
| + return statusCode; |
| + } |
| + |
| + /** |
| + * Returns all http headers from this response |
| + * |
| + * @return response code |
| + */ |
| + public List getResponseHeaders() { |
| + return responseHeaders; |
| + } |
| +} |
| diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpTransportSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpTransportSE.java |
| index d92ac09..920ca60 100644 |
| --- a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpTransportSE.java |
| +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpTransportSE.java |
| @@ -25,24 +25,21 @@ |
| |
| package org.ksoap2.transport; |
| |
| -import java.util.List; |
| -import java.util.zip.GZIPInputStream; |
| +import org.ksoap2.HeaderProperty; |
| +import org.ksoap2.SoapEnvelope; |
| +import org.ksoap2.serialization.*; |
| +import org.xmlpull.v1.XmlPullParserException; |
| + |
| import java.io.*; |
| -import java.net.MalformedURLException; |
| import java.net.Proxy; |
| -import java.net.URL; |
| - |
| -import org.ksoap2.*; |
| -import org.ksoap2.serialization.SoapSerializationEnvelope; |
| -import org.xmlpull.v1.*; |
| +import java.util.*; |
| +import java.util.zip.GZIPInputStream; |
| |
| /** |
| * A J2SE based HttpTransport layer. |
| */ |
| public class HttpTransportSE extends Transport { |
| |
| - private ServiceConnection serviceConnection; |
| - |
| /** |
| * Creates instance of HttpTransportSE with set url |
| * |
| @@ -107,249 +104,254 @@ public class HttpTransportSE extends Transport { |
| * the desired soapAction |
| * @param envelope |
| * the envelope containing the information for the soap call. |
| + * @throws HttpResponseException |
| * @throws IOException |
| * @throws XmlPullParserException |
| */ |
| - public void call(String soapAction, SoapEnvelope envelope) throws IOException, |
| - XmlPullParserException { |
| - |
| + public void call(String soapAction, SoapEnvelope envelope) |
| + throws HttpResponseException, IOException, XmlPullParserException { |
| + |
| call(soapAction, envelope, null); |
| } |
| |
| + public List call(String soapAction, SoapEnvelope envelope, List headers) |
| + throws HttpResponseException, IOException, XmlPullParserException { |
| + return call(soapAction, envelope, headers, null); |
| + } |
| + |
| /** |
| - * |
| - * set the desired soapAction header field |
| - * |
| + * Perform a soap call with a given namespace and the given envelope providing |
| + * any extra headers that the user requires such as cookies. Headers that are |
| + * returned by the web service will be returned to the caller in the form of a |
| + * <code>List</code> of <code>HeaderProperty</code> instances. |
| + * |
| * @param soapAction |
| - * the desired soapAction |
| + * the namespace with which to perform the call in. |
| * @param envelope |
| - * the envelope containing the information for the soap call. |
| + * the envelope the contains the information for the call. |
| * @param headers |
| - * a list of HeaderProperties to be http header properties when establishing the connection |
| + * <code>List</code> of <code>HeaderProperty</code> headers to send with the SOAP request. |
| + * @param outputFile |
| + * a file to stream the response into rather than parsing it, streaming happens when file is not null |
| * |
| - * @return <code>CookieJar</code> with any cookies sent by the server |
| - * @throws IOException |
| - * @throws XmlPullParserException |
| + * @return Headers returned by the web service as a <code>List</code> of |
| + * <code>HeaderProperty</code> instances. |
| + * |
| + * @throws HttpResponseException |
| + * an IOException when Http response code is different from 200 |
| */ |
| - public List call(String soapAction, SoapEnvelope envelope, List headers) |
| - throws IOException, XmlPullParserException { |
| + public List call(String soapAction, SoapEnvelope envelope, List headers, File outputFile) |
| + throws HttpResponseException, IOException, XmlPullParserException { |
| |
| if (soapAction == null) { |
| soapAction = "\"\""; |
| } |
| |
| - System.out.println("call action:" + soapAction); |
| byte[] requestData = createRequestData(envelope, "UTF-8"); |
| |
| - if (requestData != null) { |
| - requestDump = debug ? new String(requestData) : null; |
| - } |
| - else { |
| - requestDump = null; |
| - } |
| + requestDump = debug ? new String(requestData) : null; |
| responseDump = null; |
| - |
| - System.out.println("requestDump:" + requestDump); |
| + System.out.println("requestDump: " + requestDump); |
| ServiceConnection connection = getServiceConnection(); |
| - System.out.println("connection:" + connection); |
| |
| connection.setRequestProperty("User-Agent", USER_AGENT); |
| // SOAPAction is not a valid header for VER12 so do not add |
| // it |
| // @see "http://code.google.com/p/ksoap2-android/issues/detail?id=67 |
| - System.out.println("envelope:" + envelope); |
| - if (envelope != null) { |
| - if (envelope.version != SoapSerializationEnvelope.VER12) { |
| - connection.setRequestProperty("SOAPAction", soapAction); |
| - } |
| + if (envelope.version != SoapSerializationEnvelope.VER12) { |
| + connection.setRequestProperty("SOAPAction", soapAction); |
| + } |
| |
| - if (envelope.version == SoapSerializationEnvelope.VER12) { |
| - connection.setRequestProperty("Content-Type", CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8); |
| - } else { |
| - connection.setRequestProperty("Content-Type", CONTENT_TYPE_XML_CHARSET_UTF_8); |
| - } |
| + if (envelope.version == SoapSerializationEnvelope.VER12) { |
| + connection.setRequestProperty("Content-Type", CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8); |
| + } else { |
| + connection.setRequestProperty("Content-Type", CONTENT_TYPE_XML_CHARSET_UTF_8); |
| + } |
| |
| - connection.setRequestProperty("Connection", "close"); |
| - connection.setRequestProperty("Accept-Encoding", "gzip"); |
| - connection.setRequestProperty("Content-Length", "" + requestData.length); |
| + // this seems to cause issues so we are removing it |
| + //connection.setRequestProperty("Connection", "close"); |
| + connection.setRequestProperty("Accept-Encoding", "gzip"); |
| |
| - //M: Retry for HTTP Authentication |
| - //connection.setFixedLengthStreamingMode(requestData.length); |
| |
| - // Pass the headers provided by the user along with the call |
| - if (headers != null) { |
| - for (int i = 0; i < headers.size(); i++) { |
| - HeaderProperty hp = (HeaderProperty) headers.get(i); |
| - connection.setRequestProperty(hp.getKey(), hp.getValue()); |
| - } |
| + // Pass the headers provided by the user along with the call |
| + if (headers != null) { |
| + for (int i = 0; i < headers.size(); i++) { |
| + HeaderProperty hp = (HeaderProperty) headers.get(i); |
| + connection.setRequestProperty(hp.getKey(), hp.getValue()); |
| } |
| - |
| - connection.setRequestMethod("POST"); |
| - |
| - } |
| - else { |
| - connection.setRequestProperty("Connection", "close"); |
| - connection.setRequestProperty("Accept-Encoding", "gzip"); |
| - connection.setRequestMethod("GET"); |
| } |
| |
| - if (requestData != null) { |
| - OutputStream os = connection.openOutputStream(); |
| - |
| - os.write(requestData, 0, requestData.length); |
| - os.flush(); |
| - os.close(); |
| - requestData = null; |
| - } |
| - InputStream is; |
| + connection.setRequestMethod("POST"); |
| + sendData(requestData, connection,envelope); |
| + requestData = null; |
| + InputStream is = null; |
| List retHeaders = null; |
| + byte[] buf = null; // To allow releasing the resource after used |
| + int contentLength = 8192; // To determine the size of the response and adjust buffer size |
| boolean gZippedContent = false; |
| - boolean bcaCert = false; |
| + boolean xmlContent = false; |
| + int status = connection.getResponseCode(); |
| |
| try { |
| retHeaders = connection.getResponseProperties(); |
| - System.out.println("[HttpTransportSE] retHeaders = " + retHeaders); |
| + |
| for (int i = 0; i < retHeaders.size(); i++) { |
| - HeaderProperty hp = (HeaderProperty) retHeaders.get(i); |
| + HeaderProperty hp = (HeaderProperty)retHeaders.get(i); |
| // HTTP response code has null key |
| if (null == hp.getKey()) { |
| continue; |
| } |
| + |
| + // If we know the size of the response, we should use the size to initiate vars |
| + if (hp.getKey().equalsIgnoreCase("content-length") ) { |
| + if ( hp.getValue() != null ) { |
| + try { |
| + contentLength = Integer.parseInt( hp.getValue() ); |
| + } catch ( NumberFormatException nfe ) { |
| + contentLength = 8192; |
| + } |
| + } |
| + } |
| + |
| + |
| + // Check the content-type header to see if we're getting back XML, in case of a |
| + // SOAP fault on 500 codes |
| + if (hp.getKey().equalsIgnoreCase("Content-Type") |
| + && hp.getValue().contains("xml")) { |
| + xmlContent = true; |
| + } |
| + |
| + |
| // ignoring case since users found that all smaller case is used on some server |
| // and even if it is wrong according to spec, we rather have it work.. |
| if (hp.getKey().equalsIgnoreCase("Content-Encoding") |
| - && hp.getValue().equalsIgnoreCase("gzip")) { |
| + && hp.getValue().equalsIgnoreCase("gzip")) { |
| gZippedContent = true; |
| } |
| } |
| - if (gZippedContent) { |
| - is = getUnZippedInputStream(connection.openInputStream()); |
| - } else { |
| - is = connection.openInputStream(); |
| - } |
| - } catch (IOException e) { |
| - if (gZippedContent) { |
| - is = getUnZippedInputStream(connection.getErrorStream()); |
| - } else { |
| - is = connection.getErrorStream(); |
| - } |
| |
| - if (is == null) { |
| - connection.disconnect(); |
| - throw (e); |
| + //first check the response code.... |
| + if (status != 200 && status != 202) { |
| + //202 is a correct status returned by WCF OneWay operation |
| + throw new HttpResponseException("HTTP request failed, HTTP status: " + status, status,retHeaders); |
| } |
| - } |
| - |
| - if (debug) { |
| - ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| - byte[] buf = new byte[8192]; |
| |
| - while (true) { |
| - int rd = is.read(buf, 0, 8192); |
| - if (rd == -1) { |
| - break; |
| + if (contentLength > 0) { |
| + if (gZippedContent) { |
| + is = getUnZippedInputStream( |
| + new BufferedInputStream(connection.openInputStream(),contentLength)); |
| + } else { |
| + is = new BufferedInputStream(connection.openInputStream(),contentLength); |
| + } |
| + } |
| + } catch (IOException e) { |
| + if (contentLength > 0) { |
| + if(gZippedContent) { |
| + is = getUnZippedInputStream( |
| + new BufferedInputStream(connection.getErrorStream(),contentLength)); |
| + } else { |
| + is = new BufferedInputStream(connection.getErrorStream(),contentLength); |
| } |
| - bos.write(buf, 0, rd); |
| } |
| |
| - bos.flush(); |
| - buf = bos.toByteArray(); |
| + if ( e instanceof HttpResponseException) { |
| + if (!xmlContent) { |
| + if (debug && is != null) { |
| + //go ahead and read the error stream into the debug buffers/file if needed. |
| + readDebug(is, contentLength, outputFile); |
| + } |
| |
| - responseDump = new String(buf); |
| + //we never want to drop through to attempting to parse the HTTP error stream as a SOAP response. |
| + connection.disconnect(); |
| + throw e; |
| + } |
| + } |
| + } |
| |
| - System.out.println("responseDump:" + responseDump); |
| - is.close(); |
| - is = new ByteArrayInputStream(buf); |
| + if (debug) { |
| + is = readDebug(is, contentLength, outputFile); |
| } |
| |
| - if (envelope != null) { |
| - parseResponse(envelope, is); |
| + if(is!=null) |
| + { |
| + parseResponse(envelope, is,retHeaders); |
| } |
| |
| + // release all resources |
| + // input stream is will be released inside parseResponse |
| + is = null; |
| + buf = null; |
| + //This fixes Issue 173 read my explanation here: https://code.google.com/p/ksoap2-android/issues/detail?id=173 |
| + connection.disconnect(); |
| + connection = null; |
| return retHeaders; |
| } |
| |
| - private InputStream getUnZippedInputStream(InputStream inputStream) throws IOException { |
| - /* workaround for Android 2.3 |
| - (see http://stackoverflow.com/questions/5131016/) |
| - */ |
| - try { |
| - return (GZIPInputStream) inputStream; |
| - } catch (ClassCastException e) { |
| - return new GZIPInputStream(inputStream); |
| - } |
| - } |
| + protected void sendData(byte[] requestData, ServiceConnection connection, SoapEnvelope envelope) |
| + throws IOException |
| + { |
| + connection.setRequestProperty("Content-Length", "" + requestData.length); |
| + connection.setFixedLengthStreamingMode(requestData.length); |
| |
| - public ServiceConnection getServiceConnection() throws IOException { |
| - if (serviceConnection == null) { |
| - System.out.println("new ServiceConnectionSE:" + proxy + " " + url + " " + timeout); |
| - serviceConnection = new ServiceConnectionSE(proxy, url, timeout); |
| - } |
| - return serviceConnection; |
| + OutputStream os = connection.openOutputStream(); |
| + os.write(requestData, 0, requestData.length); |
| + os.flush(); |
| + os.close(); |
| } |
| |
| - public String getHost() { |
| - |
| - String retVal = null; |
| - |
| - try { |
| - retVal = new URL(url).getHost(); |
| - } catch (MalformedURLException e) { |
| - e.printStackTrace(); |
| - } |
| - |
| - return retVal; |
| + protected void parseResponse(SoapEnvelope envelope, InputStream is,List returnedHeaders) |
| + throws XmlPullParserException, IOException |
| + { |
| + parseResponse(envelope, is); |
| } |
| |
| - public int getPort() { |
| - |
| - int retVal = -1; |
| |
| - try { |
| - retVal = new URL(url).getPort(); |
| - } catch (MalformedURLException e) { |
| - e.printStackTrace(); |
| + private InputStream readDebug(InputStream is, int contentLength, File outputFile) throws IOException { |
| + OutputStream bos; |
| + if (outputFile != null) { |
| + bos = new FileOutputStream(outputFile); |
| + } else { |
| + // If known use the size if not use default value |
| + bos = new ByteArrayOutputStream( (contentLength > 0 ) ? contentLength : 256*1024); |
| } |
| |
| - return retVal; |
| - } |
| - |
| - public String getPath() { |
| - |
| - String retVal = null; |
| + byte[] buf = new byte[256]; |
| |
| - try { |
| - retVal = new URL(url).getPath(); |
| - } catch (MalformedURLException e) { |
| - e.printStackTrace(); |
| + while (true) { |
| + int rd = is.read(buf, 0, 256); |
| + if (rd == -1) { |
| + break; |
| + } |
| + bos.write(buf, 0, rd); |
| } |
| |
| - return retVal; |
| - } |
| - |
| - public String getQuery() { |
| - |
| - String retVal = null; |
| - |
| - try { |
| - retVal = new URL(url).getQuery(); |
| - } catch (MalformedURLException e) { |
| - e.printStackTrace(); |
| + bos.flush(); |
| + if (bos instanceof ByteArrayOutputStream) { |
| + buf = ((ByteArrayOutputStream) bos).toByteArray(); |
| + } |
| + bos = null; |
| + responseDump = new String(buf); |
| + is.close(); |
| + System.out.println("responseDump: " + requestDump); |
| + if (outputFile != null) { |
| + return new FileInputStream(outputFile); |
| + } else { |
| + return new ByteArrayInputStream(buf); |
| } |
| - |
| - return retVal; |
| } |
| |
| - /** |
| - * @hide |
| - */ |
| - public byte[] getRequestData(SoapEnvelope envelope, String encoding) { |
| + private InputStream getUnZippedInputStream(InputStream inputStream) throws IOException { |
| + /* workaround for Android 2.3 |
| + (see http://stackoverflow.com/questions/5131016/) |
| + */ |
| try { |
| - return createRequestData(envelope, encoding); |
| - } catch (Exception e) { |
| - e.printStackTrace(); |
| + return (GZIPInputStream) inputStream; |
| + } catch (ClassCastException e) { |
| + return new GZIPInputStream(inputStream); |
| } |
| + } |
| |
| - return null; |
| + public ServiceConnection getServiceConnection() throws IOException { |
| + return new ServiceConnectionSE(proxy, url, timeout); |
| } |
| } |
| diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSE.java |
| index 9ad9ba9..376c7d8 100644 |
| --- a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSE.java |
| +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSE.java |
| @@ -1,21 +1,16 @@ |
| |
| package org.ksoap2.transport; |
| |
| +import org.ksoap2.HeaderProperty; |
| + |
| +import javax.net.ssl.HttpsURLConnection; |
| +import javax.net.ssl.SSLSocketFactory; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| +import java.net.Proxy; |
| import java.net.URL; |
| -import java.util.Iterator; |
| -import java.util.LinkedList; |
| -import java.util.Map; |
| -import java.util.List; |
| -import java.util.Set; |
| - |
| -import javax.net.ssl.HostnameVerifier; |
| -import javax.net.ssl.SSLSocketFactory; |
| -import javax.net.ssl.HttpsURLConnection; |
| -//import com.android.okhttp.internal.http.HttpsURLConnectionImpl; |
| -import org.ksoap2.HeaderProperty; |
| +import java.util.*; |
| |
| /** |
| * HttpsServiceConnectionSE is a service connection that uses a https url connection and requires explicit setting of |
| @@ -49,10 +44,29 @@ public class HttpsServiceConnectionSE implements ServiceConnection { |
| * @param timeout the timeout for the connection in milliseconds |
| * @throws IOException |
| */ |
| - public HttpsServiceConnectionSE(String host, int port, String file, |
| - int timeout) throws IOException { |
| - connection = (HttpsURLConnection) new URL(HttpsTransportSE.PROTOCOL, host, port, file) |
| - .openConnection(); |
| + public HttpsServiceConnectionSE(String host, int port, String file, int timeout) throws IOException { |
| + this(null, host, port, file, timeout); |
| + } |
| + |
| + /** |
| + * Create the transport with the supplied parameters. |
| + * @param proxy proxy server to use |
| + * @param host the name of the host e.g. webservices.somewhere.com |
| + * @param port the http port to connect on |
| + * @param file the path to the file on the webserver that represents the |
| + * webservice e.g. /api/services/myservice.jsp |
| + * @param timeout the timeout for the connection in milliseconds |
| + * @throws IOException |
| + */ |
| + public HttpsServiceConnectionSE(Proxy proxy, String host, int port, String file, int timeout) throws IOException { |
| + |
| + if (proxy == null) { |
| + connection = (HttpsURLConnection) new URL(HttpsTransportSE.PROTOCOL, host, port, file).openConnection(); |
| + } else { |
| + connection = |
| + (HttpsURLConnection) new URL(HttpsTransportSE.PROTOCOL, host, port, file).openConnection(proxy); |
| + } |
| + |
| updateConnectionParameters(timeout); |
| } |
| |
| @@ -89,6 +103,10 @@ public class HttpsServiceConnectionSE implements ServiceConnection { |
| return retList; |
| } |
| |
| + public int getResponseCode() throws IOException { |
| + return connection.getResponseCode(); |
| + } |
| + |
| public void setRequestProperty(String key, String value) { |
| connection.setRequestProperty(key, value); |
| } |
| @@ -101,6 +119,11 @@ public class HttpsServiceConnectionSE implements ServiceConnection { |
| connection.setFixedLengthStreamingMode(contentLength); |
| } |
| |
| + public void setChunkedStreamingMode() { |
| + connection.setChunkedStreamingMode(0); |
| + } |
| + |
| + |
| public OutputStream openOutputStream() throws IOException { |
| return connection.getOutputStream(); |
| } |
| @@ -128,9 +151,4 @@ public class HttpsServiceConnectionSE implements ServiceConnection { |
| public void setSSLSocketFactory(SSLSocketFactory sf) { |
| connection.setSSLSocketFactory(sf); |
| } |
| - |
| - public void setHostnameVerifier(HostnameVerifier v) { |
| - connection.setHostnameVerifier(v); |
| - } |
| - |
| } |
| diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsTransportSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsTransportSE.java |
| index d220ac9..a7d7023 100644 |
| --- a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsTransportSE.java |
| +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsTransportSE.java |
| @@ -1,8 +1,8 @@ |
| - |
| package org.ksoap2.transport; |
| |
| import java.io.IOException; |
| import java.net.MalformedURLException; |
| +import java.net.Proxy; |
| import java.net.URL; |
| |
| /** |
| @@ -14,17 +14,31 @@ import java.net.URL; |
| public class HttpsTransportSE extends HttpTransportSE { |
| |
| static final String PROTOCOL = "https"; |
| + private static final String PROTOCOL_FULL = PROTOCOL + "://"; |
| + |
| + //connection instance, used for setting the SSLSocketFactory |
| + private HttpsServiceConnectionSE connection; |
| |
| - private ServiceConnection serviceConnection = null; |
| - private final String host; |
| - private final int port; |
| - private final String file; |
| - private final int timeout; |
| + protected final String host; |
| + protected final int port; |
| + protected final String file; |
| |
| - public HttpsTransportSE(String host, int port, String file, int timeout) { |
| - super(HttpsTransportSE.PROTOCOL + "://" + host + ":" + port + file); |
| - System.out.println("Establistion connection to: " + HttpsTransportSE.PROTOCOL + "://" |
| - + host + ":" + port + file); |
| + public HttpsTransportSE (String host, int port, String file, int timeout) { |
| + super(HttpsTransportSE.PROTOCOL_FULL + host + ":" + port + file, timeout); |
| + this.host = host; |
| + this.port = port; |
| + this.file = file; |
| + } |
| + |
| + /** |
| + * Creates instance of HttpTransportSE with set url and defines a |
| + * proxy server to use to access it |
| + * |
| + * @param proxy |
| + * Proxy information or <code>null</code> for direct access |
| + */ |
| + public HttpsTransportSE(Proxy proxy, String host, int port, String file, int timeout) { |
| + super(proxy, HttpsTransportSE.PROTOCOL_FULL + host + ":" + port + file); |
| this.host = host; |
| this.port = port; |
| this.file = file; |
| @@ -37,48 +51,11 @@ public class HttpsTransportSE extends HttpTransportSE { |
| */ |
| public ServiceConnection getServiceConnection() throws IOException |
| { |
| - if (serviceConnection == null) { |
| - serviceConnection = new HttpsServiceConnectionSE(host, port, file, timeout); |
| - } |
| - return serviceConnection; |
| - } |
| - |
| - public String getHost() { |
| - |
| - String retVal = null; |
| - |
| - try { |
| - retVal = new URL(url).getHost(); |
| - } catch (MalformedURLException e) { |
| - e.printStackTrace(); |
| + if(connection != null) { |
| + return connection; |
| + } else { |
| + connection = new HttpsServiceConnectionSE(proxy, host, port, file, timeout); |
| + return connection; |
| } |
| - |
| - return retVal; |
| - } |
| - |
| - public int getPort() { |
| - |
| - int retVal = -1; |
| - |
| - try { |
| - retVal = new URL(url).getPort(); |
| - } catch (MalformedURLException e) { |
| - e.printStackTrace(); |
| - } |
| - |
| - return retVal; |
| - } |
| - |
| - public String getPath() { |
| - |
| - String retVal = null; |
| - |
| - try { |
| - retVal = new URL(url).getPath(); |
| - } catch (MalformedURLException e) { |
| - e.printStackTrace(); |
| - } |
| - |
| - return retVal; |
| } |
| } |
| diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpsTransportSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpsTransportSE.java |
| index 287fed1..65ba582 100644 |
| --- a/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpsTransportSE.java |
| +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpsTransportSE.java |
| @@ -24,18 +24,8 @@ import java.io.IOException; |
| */ |
| public class KeepAliveHttpsTransportSE extends HttpsTransportSE |
| { |
| - private final String host; |
| - private final int port; |
| - private final String file; |
| - private final int timeout; |
| - private ServiceConnection serviceConnection; |
| - |
| - public KeepAliveHttpsTransportSE(String host, int port, String file, int timeout) { |
| + public KeepAliveHttpsTransportSE (String host, int port, String file, int timeout) { |
| super(host, port, file, timeout); |
| - this.host = host; |
| - this.port = port; |
| - this.file = file; |
| - this.timeout = timeout; |
| } |
| |
| /** |
| @@ -47,11 +37,9 @@ public class KeepAliveHttpsTransportSE extends HttpsTransportSE |
| //@Override |
| public ServiceConnection getServiceConnection() throws IOException |
| { |
| - if (serviceConnection == null) { |
| - serviceConnection = new HttpsServiceConnectionSEIgnoringConnectionClose(host, port, |
| - file, timeout); |
| - serviceConnection.setRequestProperty("Connection", "keep-alive"); |
| - } |
| + ServiceConnection serviceConnection = |
| + new HttpsServiceConnectionSEIgnoringConnectionClose(host, port, file, timeout); |
| + serviceConnection.setRequestProperty("Connection", "keep-alive"); |
| return serviceConnection; |
| } |
| |
| diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/ServiceConnectionSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/ServiceConnectionSE.java |
| index 029ee9a..bfdfe11 100644 |
| --- a/ksoap2-j2se/src/main/java/org/ksoap2/transport/ServiceConnectionSE.java |
| +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/ServiceConnectionSE.java |
| @@ -21,16 +21,16 @@ |
| |
| package org.ksoap2.transport; |
| |
| -import java.io.*; |
| -import java.net.*; |
| -import java.util.Iterator; |
| -import java.util.LinkedList; |
| -import java.util.List; |
| -import java.util.Map; |
| -import java.util.Set; |
| - |
| import org.ksoap2.HeaderProperty; |
| |
| +import java.io.IOException; |
| +import java.io.InputStream; |
| +import java.io.OutputStream; |
| +import java.net.HttpURLConnection; |
| +import java.net.Proxy; |
| +import java.net.URL; |
| +import java.util.*; |
| + |
| /** |
| * Connection for J2SE environments. |
| */ |
| @@ -80,23 +80,29 @@ public class ServiceConnectionSE implements ServiceConnection { |
| connection.disconnect(); |
| } |
| |
| - public List getResponseProperties() { |
| - Map properties = connection.getHeaderFields(); |
| - Set keys = properties.keySet(); |
| + public List getResponseProperties() throws IOException { |
| List retList = new LinkedList(); |
| |
| - for (Iterator i = keys.iterator(); i.hasNext();) { |
| - String key = (String) i.next(); |
| - List values = (List) properties.get(key); |
| - |
| - for (int j = 0; j < values.size(); j++) { |
| - retList.add(new HeaderProperty(key, (String) values.get(j))); |
| + Map properties = connection.getHeaderFields(); |
| + if(properties != null) { |
| + Set keys = properties.keySet(); |
| + for (Iterator i = keys.iterator(); i.hasNext();) { |
| + String key = (String) i.next(); |
| + List values = (List) properties.get(key); |
| + |
| + for (int j = 0; j < values.size(); j++) { |
| + retList.add(new HeaderProperty(key, (String) values.get(j))); |
| + } |
| } |
| } |
| |
| return retList; |
| } |
| |
| + public int getResponseCode() throws IOException { |
| + return connection.getResponseCode(); |
| + } |
| + |
| public void setRequestProperty(String string, String soapAction) { |
| connection.setRequestProperty(string, soapAction); |
| } |
| @@ -116,6 +122,10 @@ public class ServiceConnectionSE implements ServiceConnection { |
| connection.setFixedLengthStreamingMode(contentLength); |
| } |
| |
| + public void setChunkedStreamingMode() { |
| + connection.setChunkedStreamingMode(0); |
| + } |
| + |
| public OutputStream openOutputStream() throws IOException { |
| return connection.getOutputStream(); |
| } |
| -- |
| 2.17.0.441.gb46fe60e1d-goog |
| |