diff --git a/.gitignore b/.gitignore index 7f3abbd0..a168dc71 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,14 @@ bin/ target*/ *.log +out +*~ # Project config files .settings/ .project .classpath - +.idea/ +*.iml +.checkstyle +.DS_Store diff --git a/.looper.yml b/.looper.yml new file mode 100644 index 00000000..47824c20 --- /dev/null +++ b/.looper.yml @@ -0,0 +1,11 @@ +tools: + jdk: + - 8 + maven: + - 3.3.9 + +flows: + master: + - (on master, name build) mvn clean install -B + pr: + - call: master diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..b20a55a7 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.3"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + " .jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..e89f07c2 Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..1703626c --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..cf031523 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +sudo: false +language: java +jdk: openjdk7 + +script: ./mvnw clean install + diff --git a/LICENSE.txt b/LICENSE.txt index 09356f63..97c3fa33 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,3 +1,4 @@ +Copyright (c) 2009-2012 the ksoap2-android project (http://code.google.com/p/ksoap2-android) Copyright (c) 2006, James Seigel, Calgary, AB., Canada Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany @@ -19,3 +20,31 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Further patches have been contributed under the same license by: + +Jorge Jimenez http://groups.google.com/groups/profile?enc_user=Ey3jEg8AAACg1wBgVrjM04pX08V0u_rp +Karl Michael Davis https://github.com/karlmdavis +Manfred Moser http://www.simpligility.com +Matt Fletcher http://www.atomicobject.com/pages/Matt+Fletcher +Zachary Kurmasz http://www.cis.gvsu.edu/~kurmasz/ +Juraj Ivančić" +Edgar Hernández García +Jim Redman +Nebojsa Licina +Rainer Klier +Andreas Mattisson +Mark Radbourne +Andrew Oppenlander https://github.com/Usagimaru57 +Petter Uvesten http://www.everichon.com +John Lindemann +Finn Larsen +Dawid Drozd https://github.com/gelldur +Konrad Barth +Nikolay Ivanets <> https://github.com/StenaviN +Sergej Koščejev <> https://github.com/sergej-koscejev +Anatoliy Shuba https://github.com/AShuba +Jose Castellanos Molina https://github.com/matlock08 +Dominik Maier domenukk@googlemail.com https://github.com/domenukk +Vadim Kotov vkotovv@gmail.com https://github.com/vkotovv +Ahmad Maziz Esa maziz.esa@gmail.com https://github.com/MazizEsa + diff --git a/README.asciidoc b/README.asciidoc new file mode 100644 index 00000000..d68848d6 --- /dev/null +++ b/README.asciidoc @@ -0,0 +1,30 @@ +== KSOAP2-ANDROID + +This is the master code repository for the ksoap2-android project. For further information see: + +=== Project website + +For documentation, links, issue tracker, wiki and so on: + +http://simpligility.github.io/ksoap2-android/[http://simpligility.github.io/ksoap2-android/] + +=== Mailing list + +For discussions with others users, questions and more: + +http://groups.google.com/group/ksoap2-android[http://groups.google.com/group/ksoap2-android] + +=== CI Build + +image:https://travis-ci.org/simpligility/ksoap2-android.png["Build Status", link="https://travis-ci.org/simpligility/ksoap2-android"] + +=== Contributions + +We welcome your feature enhancements and bug fixes in pull requests! + +=== License + +This project uses the MIT license. See LICENSE.txt and +http://simpligility.github.io/ksoap2-android/license-information.html[http://simpligility.github.io/ksoap2-android/license-information.html] +for more information. + diff --git a/build-tools/pom.xml b/build-tools/pom.xml new file mode 100644 index 00000000..1d470ffc --- /dev/null +++ b/build-tools/pom.xml @@ -0,0 +1,12 @@ + + + 4.0.0 + + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + + + build-tools + diff --git a/build-tools/src/main/resources/simpligility/checkstyle.xml b/build-tools/src/main/resources/simpligility/checkstyle.xml new file mode 100644 index 00000000..6fa1d770 --- /dev/null +++ b/build-tools/src/main/resources/simpligility/checkstyle.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipseFormatter.xml b/eclipseFormatter.xml deleted file mode 100644 index 78707643..00000000 --- a/eclipseFormatter.xml +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/eclipseTemplates.xml b/eclipseTemplates.xml deleted file mode 100644 index 99f9252d..00000000 --- a/eclipseTemplates.xml +++ /dev/null @@ -1,30 +0,0 @@ - \ No newline at end of file diff --git a/ksoap2-android-assembly/pom.xml b/ksoap2-android-assembly/pom.xml index 9915df14..a234b00d 100644 --- a/ksoap2-android-assembly/pom.xml +++ b/ksoap2-android-assembly/pom.xml @@ -1,47 +1,49 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-android-assembly - ksoap2-android-assembly - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - com.google.code.ksoap2-android - ksoap2-android - - + ksoap2-android-assembly + jar - - - - maven-assembly-plugin - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - + ksoap2-android-assembly + + + + + com.google.code.ksoap2-android + ksoap2-android + ${project.version} + + + + + + + maven-assembly-plugin + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + diff --git a/ksoap2-android/.gitignore b/ksoap2-android/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-android/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-android/pom.xml b/ksoap2-android/pom.xml index cdff2f56..97e6458c 100644 --- a/ksoap2-android/pom.xml +++ b/ksoap2-android/pom.xml @@ -1,41 +1,47 @@ + - 4.0.0 + 4.0.0 - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - ksoap2-android - ksoap2-android - jar - - + ksoap2-android + jar - - - com.google.code.ksoap2-android - ksoap2-j2se - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - + ksoap2-android + + + + + com.google.code.ksoap2-android + ksoap2-j2se + ${project.version} + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + diff --git a/ksoap2-android/src/main/java/org/ksoap2/transport/AndroidHttpTransport.java b/ksoap2-android/src/main/java/org/ksoap2/transport/AndroidHttpTransport.java deleted file mode 100644 index 01506960..00000000 --- a/ksoap2-android/src/main/java/org/ksoap2/transport/AndroidHttpTransport.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.ksoap2.transport; - -import java.io.IOException; - -/** - * This is a simple extension of the {@link HttpTransportSE} class. It provides the exact same functionality - * as that class and is provided purely for backwards-compatibility purposes. It will likely be deprecated at - * some point in the near future. - */ -public class AndroidHttpTransport extends HttpTransportSE -{ - /** - * @see HttpTransportSE#HttpTransportSE(String) - */ - public AndroidHttpTransport(String url) - { - super(url); - } - - /** - * @see org.ksoap2.transport.HttpTransportSE#getServiceConnection() - */ - @Override - protected ServiceConnection getServiceConnection() throws IOException - { - return new AndroidServiceConnection(super.url); - } -} diff --git a/ksoap2-android/src/main/java/org/ksoap2/transport/AndroidServiceConnection.java b/ksoap2-android/src/main/java/org/ksoap2/transport/AndroidServiceConnection.java deleted file mode 100644 index 47a95a1a..00000000 --- a/ksoap2-android/src/main/java/org/ksoap2/transport/AndroidServiceConnection.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.ksoap2.transport; - -import java.io.IOException; - -/** - * This is a simple extension of the {@link HttpTransportSE} class. It provides the exact same functionality - * as that class and is provided purely for backwards-compatibility purposes. It will likely be deprecated at - * some point in the near future. - */ -public class AndroidServiceConnection extends ServiceConnectionSE -{ - /** - * @see ServiceConnectionSE#ServiceConnectionSE(String) - */ - public AndroidServiceConnection(String url) throws IOException - { - super(url); - } -} diff --git a/ksoap2-android/src/test/java/org/ksoap2/NewApiSample.java b/ksoap2-android/src/test/java/org/ksoap2/NewApiSample.java deleted file mode 100644 index c8997c16..00000000 --- a/ksoap2-android/src/test/java/org/ksoap2/NewApiSample.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.ksoap2; - -/** - * Just a scratchpad for some API ideas. - */ -public class NewApiSample -{ - -} diff --git a/ksoap2-base/.gitignore b/ksoap2-base/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-base/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-base/pom.xml b/ksoap2-base/pom.xml index 6bbc0ec4..b367ed45 100644 --- a/ksoap2-base/pom.xml +++ b/ksoap2-base/pom.xml @@ -1,50 +1,55 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-base - ksoap2-base - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - net.sourceforge.kxml - kxml - - - net.sourceforge.kobjects - kobjects-j2me - - - - junit - junit - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - + ksoap2-base + jar + ksoap2-base + + + + + + net.sourceforge.kxml + kxml + + + net.sourceforge.kobjects + kobjects-j2me + + + + junit + junit + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + diff --git a/ksoap2-base/src/main/java/org/ksoap2/HeaderProperty.java b/ksoap2-base/src/main/java/org/ksoap2/HeaderProperty.java new file mode 100644 index 00000000..566ef09b --- /dev/null +++ b/ksoap2-base/src/main/java/org/ksoap2/HeaderProperty.java @@ -0,0 +1,27 @@ +package org.ksoap2; + +/** + * HeaderProperty is a key - value pojo for storing http header properties. + */ +public class HeaderProperty { + private String key; + private String value; + + public HeaderProperty(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } +} diff --git a/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java b/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java index 35f61fa1..1e95aa1b 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java +++ b/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java @@ -39,8 +39,8 @@ public class SoapEnvelope { public static final int VER11 = 110; /** SOAP Version 1.2 constant */ public static final int VER12 = 120; - public static final String ENV2001 = "http://www.w3.org/2001/12/soap-envelope"; - public static final String ENC2001 = "http://www.w3.org/2001/12/soap-encoding"; + public static final String ENV2003 = "http://www.w3.org/2003/05/soap-envelope"; + public static final String ENC2003 = "http://www.w3.org/2003/05/soap-encoding"; /** Namespace constant: http://schemas.xmlsoap.org/soap/envelope/ */ public static final String ENV = "http://schemas.xmlsoap.org/soap/envelope/"; /** Namespace constant: http://schemas.xmlsoap.org/soap/encoding/ */ @@ -59,8 +59,9 @@ public class SoapEnvelope { * case and whitespace, false otherwise. */ public static boolean stringToBoolean(String booleanAsString) { - if (booleanAsString == null) + if (booleanAsString == null) { return false; + } booleanAsString = booleanAsString.trim().toLowerCase(); return (booleanAsString.equals("1") || booleanAsString.equals("true")); } @@ -116,8 +117,8 @@ public SoapEnvelope(int version) { enc = SoapEnvelope.ENC; env = SoapEnvelope.ENV; } else { - enc = SoapEnvelope.ENC2001; - env = SoapEnvelope.ENV2001; + enc = SoapEnvelope.ENC2003; + env = SoapEnvelope.ENV2003; } } @@ -127,7 +128,9 @@ public void parse(XmlPullParser parser) throws IOException, XmlPullParserExcepti parser.require(XmlPullParser.START_TAG, env, "Envelope"); encodingStyle = parser.getAttributeValue(env, "encodingStyle"); parser.nextTag(); - if (parser.getEventType() == XmlPullParser.START_TAG && parser.getNamespace().equals(env) && parser.getName().equals("Header")) { + if (parser.getEventType() == XmlPullParser.START_TAG + && parser.getNamespace().equals(env) + && parser.getName().equals("Header")) { parseHeader(parser); parser.require(XmlPullParser.END_TAG, env, "Header"); parser.nextTag(); @@ -149,23 +152,33 @@ public void parseHeader(XmlPullParser parser) throws IOException, XmlPullParserE int count = 0; for (int i = 0; i < headers.getChildCount(); i++) { Element child = headers.getElement(i); - if (child != null) + if (child != null) { count++; + } } headerIn = new Element[count]; count = 0; for (int i = 0; i < headers.getChildCount(); i++) { Element child = headers.getElement(i); - if (child != null) + if (child != null) { headerIn[count++] = child; + } } } public void parseBody(XmlPullParser parser) throws IOException, XmlPullParserException { parser.nextTag(); // insert fault generation code here - if (parser.getEventType() == XmlPullParser.START_TAG && parser.getNamespace().equals(env) && parser.getName().equals("Fault")) { - SoapFault fault = new SoapFault(); + if (parser.getEventType() == XmlPullParser.START_TAG + && parser.getNamespace().equals(env) + && parser.getName().equals("Fault")) { + + SoapFault fault; + if (this.version < SoapEnvelope.VER12) { + fault = new SoapFault(this.version); + } else { + fault = new SoapFault12(this.version); + } fault.parse(parser); bodyIn = fault; } else { @@ -210,8 +223,9 @@ public void writeHeader(XmlSerializer writer) throws IOException { * method for customized writing of the soap message body. */ public void writeBody(XmlSerializer writer) throws IOException { - if (encodingStyle != null) + if (encodingStyle != null) { writer.attribute(env, "encodingStyle", encodingStyle); + } ((Node) bodyOut).write(writer); } diff --git a/ksoap2-base/src/main/java/org/ksoap2/SoapFault.java b/ksoap2-base/src/main/java/org/ksoap2/SoapFault.java index 63cf7e20..ab131a42 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/SoapFault.java +++ b/ksoap2-base/src/main/java/org/ksoap2/SoapFault.java @@ -30,75 +30,86 @@ * Exception class encapsulating SOAP Faults */ -public class SoapFault extends IOException -{ +public class SoapFault extends IOException { - /** The SOAP fault code */ - public String faultcode; - /** The SOAP fault code */ - public String faultstring; - /** The SOAP fault code */ - public String faultactor; - /** A KDom Node holding the details of the fault */ - public Node detail; + private static final long serialVersionUID = 1011001L; + /** The SOAP fault code */ + public String faultcode; + /** The SOAP fault code */ + public String faultstring; + /** The SOAP fault code */ + public String faultactor; + /** A KDom Node holding the details of the fault */ + public Node detail; + /** an integer that holds current soap version */ + public int version; - /** Fills the fault details from the given XML stream */ - public void parse(XmlPullParser parser) throws IOException, XmlPullParserException - { - parser.require(XmlPullParser.START_TAG, SoapEnvelope.ENV, "Fault"); - while (parser.nextTag() == XmlPullParser.START_TAG) - { - String name = parser.getName(); - if (name.equals("detail")) - { - detail = new Node(); - detail.parse(parser); - continue; - } - else if (name.equals("faultcode")) - faultcode = parser.nextText(); - else if (name.equals("faultstring")) - faultstring = parser.nextText(); - else if (name.equals("faultactor")) - faultactor = parser.nextText(); - else - throw new RuntimeException("unexpected tag:" + name); - parser.require(XmlPullParser.END_TAG, null, name); - } - parser.require(XmlPullParser.END_TAG, SoapEnvelope.ENV, "Fault"); - parser.nextTag(); - } + public SoapFault() { + super(); + this.version = SoapEnvelope.VER11; + } - /** Writes the fault to the given XML stream */ - public void write(XmlSerializer xw) throws IOException - { - xw.startTag(SoapEnvelope.ENV, "Fault"); - xw.startTag(null, "faultcode"); - xw.text("" + faultcode); - xw.endTag(null, "faultcode"); - xw.startTag(null, "faultstring"); - xw.text("" + faultstring); - xw.endTag(null, "faultstring"); - xw.startTag(null, "detail"); - if (detail != null) - detail.write(xw); - xw.endTag(null, "detail"); - xw.endTag(SoapEnvelope.ENV, "Fault"); - } + public SoapFault(int version) { + super(); + this.version = version; + } - /** - * @see java.lang.Throwable#getMessage() - */ - @Override - public String getMessage() - { - return faultstring; - } + /** Fills the fault details from the given XML stream */ + public void parse(XmlPullParser parser) throws IOException, XmlPullParserException { + parser.require(XmlPullParser.START_TAG, SoapEnvelope.ENV, "Fault"); + while (parser.nextTag() == XmlPullParser.START_TAG) { + String name = parser.getName(); + if (name.equals("detail")) { + detail = new Node(); + detail.parse(parser); + // Handle case '...' + if ( parser.getNamespace().equals( SoapEnvelope.ENV ) && parser.getName().equals( "Fault" ) ) { + break; + } + continue; + } else if (name.equals("faultcode")) { + faultcode = parser.nextText(); + } else if (name.equals("faultstring")) { + faultstring = parser.nextText(); + } else if (name.equals("faultactor")) { + faultactor = parser.nextText(); + } else { + throw new RuntimeException("unexpected tag:" + name); + } + parser.require(XmlPullParser.END_TAG, null, name); + } + parser.require(XmlPullParser.END_TAG, SoapEnvelope.ENV, "Fault"); + parser.nextTag(); + } - /** Returns a simple string representation of the fault */ - public String toString() - { - return "SoapFault - faultcode: '" + faultcode + "' faultstring: '" + faultstring + "' faultactor: '" - + faultactor + "' detail: " + detail; - } + /** Writes the fault to the given XML stream */ + public void write(XmlSerializer xw) throws IOException { + xw.startTag(SoapEnvelope.ENV, "Fault"); + xw.startTag(null, "faultcode"); + xw.text("" + faultcode); + xw.endTag(null, "faultcode"); + xw.startTag(null, "faultstring"); + xw.text("" + faultstring); + xw.endTag(null, "faultstring"); + xw.startTag(null, "detail"); + if (detail != null) { + detail.write(xw); + } + xw.endTag(null, "detail"); + xw.endTag(SoapEnvelope.ENV, "Fault"); + } + + /** + * @see java.lang.Throwable#getMessage() + */ + public String getMessage() { + return faultstring; + } + + /** Returns a simple string representation of the fault */ + public String toString() { + return "SoapFault - faultcode: '" + faultcode + "' faultstring: '" + + faultstring + "' faultactor: '" + faultactor + "' detail: " + + detail; + } } diff --git a/ksoap2-base/src/main/java/org/ksoap2/SoapFault12.java b/ksoap2-base/src/main/java/org/ksoap2/SoapFault12.java new file mode 100644 index 00000000..a0fae397 --- /dev/null +++ b/ksoap2-base/src/main/java/org/ksoap2/SoapFault12.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany + * + * Copyright (c) 2011, Petter Uvesten, Everichon AB, Sweden + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO + * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.ksoap2; + +import java.io.IOException; + +import org.kxml2.kdom.Node; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +/** + * Exception class encapsulating SOAP 1.2 Faults + * + * see http://www.w3.org/TR/soap12-part1/#soapfault for explanation of fields + * + * @author Petter Uvesten + */ + +public class SoapFault12 extends SoapFault { + private static final long serialVersionUID = 1012001L; + + /** Top-level nodes */ + public Node Code; + public Node Reason; + public Node Node; + public Node Role; + public Node Detail; + + public SoapFault12() { + super(); + this.version = SoapEnvelope.VER12; + } + + public SoapFault12(int version) { + super(); + this.version = version; + } + + + /** Fills the fault details from the given XML stream */ + public void parse(XmlPullParser parser) throws IOException, XmlPullParserException + { + parseSelf(parser); + // done parsing, populate some of the legacy public members + this.faultcode = Code.getElement(SoapEnvelope.ENV2003, "Value").getText(0); + this.faultstring = Reason.getElement(SoapEnvelope.ENV2003, "Text").getText(0); + this.detail = this.Detail; + this.faultactor = null; + } + + + private void parseSelf(XmlPullParser parser) throws IOException, XmlPullParserException { + parser.require(XmlPullParser.START_TAG, SoapEnvelope.ENV2003, "Fault"); + + while (parser.nextTag() == XmlPullParser.START_TAG) { + String name = parser.getName(); + String namespace = parser.getNamespace(); + parser.nextTag(); + if (name.toLowerCase().equals("Code".toLowerCase())) { + this.Code = new Node(); + this.Code.parse(parser); + } else if (name.toLowerCase().equals("Reason".toLowerCase())) { + this.Reason = new Node(); + this.Reason.parse(parser); + } else if (name.toLowerCase().equals("Node".toLowerCase())) { + this.Node = new Node(); + this.Node.parse(parser); + } else if (name.toLowerCase().equals("Role".toLowerCase())) { + this.Role = new Node(); + this.Role.parse(parser); + } 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, namespace, name); + } + parser.require(XmlPullParser.END_TAG, SoapEnvelope.ENV2003, "Fault"); + parser.nextTag(); + + } + + /** Writes the fault to the given XML stream */ + public void write(XmlSerializer xw) throws IOException + { + xw.startTag(SoapEnvelope.ENV2003, "Fault"); + //this.Code.write(xw); + + xw.startTag(SoapEnvelope.ENV2003, "Code"); + this.Code.write(xw); + xw.endTag(SoapEnvelope.ENV2003, "Code"); + xw.startTag(SoapEnvelope.ENV2003, "Reason"); + this.Reason.write(xw); + xw.endTag(SoapEnvelope.ENV2003, "Reason"); + + if (this.Node != null) { + xw.startTag(SoapEnvelope.ENV2003, "Node"); + this.Node.write(xw); + xw.endTag(SoapEnvelope.ENV2003, "Node"); + } + if (this.Role != null) { + xw.startTag(SoapEnvelope.ENV2003, "Role"); + this.Role.write(xw); + xw.endTag(SoapEnvelope.ENV2003, "Role"); + } + + if (this.Detail != null) { + xw.startTag(SoapEnvelope.ENV2003, "Detail"); + this.Detail.write(xw); + xw.endTag(SoapEnvelope.ENV2003, "Detail"); + } + xw.endTag(SoapEnvelope.ENV2003, "Fault"); + } + + /** + * @see java.lang.Throwable#getMessage() + */ + public String getMessage() { + return Reason.getElement(SoapEnvelope.ENV2003, "Text").getText(0); + } + + /** Returns a string representation of the fault */ + public String toString() { + String reason = Reason.getElement(SoapEnvelope.ENV2003, "Text").getText(0); + String code = Code.getElement(SoapEnvelope.ENV2003, "Value").getText(0); + return "Code: " + code + ", Reason: " + reason; + } +} diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeContainer.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeContainer.java new file mode 100644 index 00000000..6081bb5a --- /dev/null +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeContainer.java @@ -0,0 +1,316 @@ +package org.ksoap2.serialization; + +import java.util.Vector; + +public class AttributeContainer implements HasAttributes{ + protected Vector attributes = new Vector(); + + /** + * Places AttributeInfo of desired attribute into a designated AttributeInfo object + * + * @param index index of desired attribute + * @param attributeInfo designated retainer of desired attribute + */ + public void getAttributeInfo(int index, AttributeInfo attributeInfo) { + AttributeInfo p = (AttributeInfo) attributes.elementAt(index); + attributeInfo.name = p.name; + attributeInfo.namespace = p.namespace; + attributeInfo.flags = p.flags; + attributeInfo.type = p.type; + attributeInfo.elementType = p.elementType; + attributeInfo.value = p.getValue(); + } + + /** + * Get the attribute at the given index + */ + public Object getAttribute(int index) { + return ((AttributeInfo) attributes.elementAt(index)).getValue(); + } + + /** + * Get the attribute's toString value. + */ + public String getAttributeAsString(int index) { + AttributeInfo attributeInfo = (AttributeInfo) attributes.elementAt(index); + return attributeInfo.getValue().toString(); + } + + /** + * Get the attribute with the given name + * + * @throws RuntimeException if the attribute does not exist + */ + public Object getAttribute(String name) { + Integer i = attributeIndex(name); + if (i != null) { + return getAttribute(i.intValue()); + } else { + throw new RuntimeException("illegal property: " + name); + } + } + + /** + * 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. + * + * @throws RuntimeException if the attribute does not exist + */ + public String getAttributeAsString(String name) { + Integer i = attributeIndex(name); + if (i != null) { + return getAttribute(i.intValue()).toString(); + } else { + throw new RuntimeException("illegal property: " + name); + } + } + + /** + * 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 + */ + public boolean hasAttribute(final String name) { + if (attributeIndex(name) != null) { + return true; + } else { + return false; + } + } + + /** + * 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 + * + * @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 name) { + Integer i = attributeIndex(name); + if (i != null) { + return getAttribute(i.intValue()); + } else { + return null; + } + } + + /** + * 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. + + * @param name + * @return the value of the attribute,s toString method if it exists; "" + * if it does not exist + */ + public Object getAttributeSafelyAsString(String name) { + Integer i = attributeIndex(name); + if (i != null) { + return getAttribute(i.intValue()).toString(); + } else { + return ""; + } + } + + /** + * 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())) { + return new Integer(i); + } + } + 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 + * + * @return the number of attributes + */ + public int getAttributeCount() { + return attributes.size(); + } + + /** + * Checks that the two objects have identical sets of attributes. + * + * @param other + * @return {@code true} of the attrubte sets are equal, {@code false} otherwise. + */ + protected boolean attributesAreEqual(AttributeContainer other) { + int numAttributes = getAttributeCount(); + if (numAttributes != other.getAttributeCount()) { + return false; + } + + for (int attribIndex = 0; attribIndex < numAttributes; attribIndex++) { + AttributeInfo thisAttrib = (AttributeInfo) this.attributes.elementAt(attribIndex); + Object thisAttribValue = thisAttrib.getValue(); + if (!other.hasAttribute(thisAttrib.getName())) { + return false; + } + Object otherAttribValue = other.getAttributeSafely(thisAttrib.getName()); + if (!thisAttribValue.equals(otherAttribValue)) { + return false; + } + } + return true; + } + + /** + * Adds a attribute (parameter) to the object. + * + * @param name The name of the attribute + * @param value the value of the attribute + * @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 + * @param value + */ + public void addAttributeIfValue(String name, Object value) { + if (value != null) { + addAttribute(name, value); + } + } + + /** + * 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.} + * + * @param attributeInfo the {@code AttributeInfo} object to add. + * @return {@code this} object. + */ + public void addAttribute(AttributeInfo attributeInfo) { + attributes.addElement(attributeInfo); + } + + /** + * Add an attributeInfo if its value is not null. + * @param attributeInfo + */ + public void addAttributeIfValue(AttributeInfo attributeInfo) { + if (attributeInfo.value != null) { + 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/AttributeInfo.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeInfo.java index cb1e7492..c722364f 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeInfo.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/AttributeInfo.java @@ -26,11 +26,11 @@ */ public class AttributeInfo extends PropertyInfo { - /** - * Constructor. - */ - public AttributeInfo() - { - super(); - } + /** + * Constructor. + */ + public AttributeInfo() + { + super(); + } } 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 e28d87bb..255126e2 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,24 +33,75 @@ */ class DM implements Marshal { - public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) throws IOException, XmlPullParserException { + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo excepted) + throws IOException, XmlPullParserException { String text = parser.nextText(); switch (name.charAt(0)) { - case 's': - return text; - case 'i': - return new Integer(Integer.parseInt(text)); - case 'l': - return new Long(Long.parseLong(text)); - case 'b': - return new Boolean(SoapEnvelope.stringToBoolean(text)); - default: - throw new RuntimeException(); + case 's': + return text; + case 'i': + return new Integer(Integer.parseInt(text)); + case 'l': + return new Long(Long.parseLong(text)); + case 'b': + return new Boolean(SoapEnvelope.stringToBoolean(text)); + default: + throw new RuntimeException(); } } + /** + * 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 + */ public void writeInstance(XmlSerializer writer, Object instance) throws IOException { - writer.text(instance.toString()); + if (instance instanceof AttributeContainer) { + AttributeContainer attributeContainer = (AttributeContainer) instance; + int cnt = attributeContainer.getAttributeCount(); + for (int counter = 0; counter < cnt; counter++) { + AttributeInfo attributeInfo = new AttributeInfo(); + attributeContainer.getAttributeInfo(counter, attributeInfo); + 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() : ""); + } + } + } + + 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 00000000..b5131382 --- /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 00000000..b35c35b7 --- /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 0f22a973..553d682e 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/KvmSerializable.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/KvmSerializable.java @@ -35,40 +35,33 @@ public interface KvmSerializable { /** - * Returns the property at a specified index (for serialization) - * - * @param index - * the specified index - * @return the serialized property + * Get the property at the given index */ 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 73d8efd2..100f1071 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/Marshal.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/Marshal.java @@ -41,7 +41,8 @@ public interface Marshal { * the namespace. * @return the object read from the xml stream. */ - public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) throws IOException, XmlPullParserException; + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) + throws IOException, XmlPullParserException; /** * Write the instance to the given XmlSerializer. In contrast to 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 9de0beb8..38cbc255 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalBase64.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalBase64.java @@ -31,7 +31,8 @@ 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) throws IOException, XmlPullParserException { + 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 534319cb..7770a545 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalDate.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalDate.java @@ -32,7 +32,8 @@ public class MarshalDate implements Marshal { public static Class DATE_CLASS = new Date().getClass(); - public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) throws IOException, XmlPullParserException { + 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 b33781e8..0c6b53e0 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalHashtable.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/MarshalHashtable.java @@ -46,7 +46,8 @@ 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) throws IOException, XmlPullParserException { + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) + throws IOException, XmlPullParserException { Hashtable instance = new Hashtable(); String elementName = parser.getName(); while (parser.nextTag() != XmlPullParser.END_TAG) { @@ -79,7 +80,7 @@ public void writeInstance(XmlSerializer writer, Object instance) throws IOExcept 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"); } } @@ -102,10 +103,11 @@ public void setProperty(int index, Object value) { } else { // already have a key or value Object resolved = resolvedIndex == 0 ? getProperty(0) : getProperty(1); - if (index == 0) + if (index == 0) { h.put(value, resolved); - else + } else { h.put(resolved, value); + } } } } diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/NullSoapObject.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/NullSoapObject.java new file mode 100644 index 00000000..8fb90374 --- /dev/null +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/NullSoapObject.java @@ -0,0 +1,39 @@ +package org.ksoap2.serialization; + +/** + * A class that implements only {@link NullSoapObject#toString()}. + * This is useful in the case where you have a {@link SoapObject} representing an optional + * property in your SOAP response.

+ * + * Example: + *
+ * 
+ * private String getAge(SoapObject person) {
+ *   return person.getPropertySafely("age").toString();
+ * }
+ * 
+ * 
+ *
    + *
  • When the person object has an {@code age} property, the {@code age} will be returned.
  • + *
  • + * When the person object does not have an {@code age} property, + * {@link SoapObject#getPropertySafely(String)} + * returns a NullSoapObject, which in turn returns {@code null} for {@link NullSoapObject#toString()}. + *
  • + *
+ * Now it is safe to always try and get the {@code age} property (assuming your downstream + * code can handle {@code age}). + */ + +public class NullSoapObject { + /** + * Overridden specifically to always return null. + * See the example in this class's description as to how this can be useful. + * + * @return {@code null} + * @see SoapObject#getPropertySafely(String) + */ + public String toString() { + return null; + } +} diff --git a/ksoap2-base/src/main/java/org/ksoap2/serialization/PropertyInfo.java b/ksoap2-base/src/main/java/org/ksoap2/serialization/PropertyInfo.java index 931592fd..d3c19cb7 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/PropertyInfo.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/PropertyInfo.java @@ -21,207 +21,252 @@ package org.ksoap2.serialization; +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; + +import java.io.IOException; +import java.io.NotSerializableException; /** * This class is used to store information about each property an implementation of KvmSerializable exposes. */ -public class PropertyInfo +public class PropertyInfo implements java.io.Serializable { - public static final Class OBJECT_CLASS = new Object().getClass(); - public static final Class STRING_CLASS = "".getClass(); - public static final Class INTEGER_CLASS = new Integer(0).getClass(); - public static final Class LONG_CLASS = new Long(0).getClass(); - public static final Class BOOLEAN_CLASS = new Boolean(true).getClass(); - public static final Class VECTOR_CLASS = new java.util.Vector().getClass(); - public static final PropertyInfo OBJECT_TYPE = new PropertyInfo(); - public static final int TRANSIENT = 1; - public static final int MULTI_REF = 2; - public static final int REF_ONLY = 4; - - /** - * Name of the property - */ - public String name; - - /** - * Namespace of this property - */ - public String namespace; - - /** - * Type of property, Transient, multi_ref, Ref_only *JHS* Note, not really used that effectively - */ - public int flags; - - /** - * The current value of this property. - */ - protected Object value; - - /** - * Type of the property/elements. Should usually be an instance of Class. - */ - public Object type = OBJECT_CLASS; - - /** - * if a property is multi-referenced, set this flag to true. - */ - public boolean multiRef; - - /** - * Element type for array properties, null if not array prop. - */ - public PropertyInfo elementType; - - public PropertyInfo() - { - } - - public void clear() - { - type = OBJECT_CLASS; - flags = 0; - name = null; - namespace = null; - } - - /** - * @return Returns the elementType. - */ - public PropertyInfo getElementType() - { - return elementType; - } - - /** - * @param elementType - * The elementType to set. - */ - public void setElementType(PropertyInfo elementType) - { - this.elementType = elementType; - } - - /** - * @return Returns the flags. - */ - public int getFlags() - { - return flags; - } - - /** - * @param flags - * The flags to set. - */ - public void setFlags(int flags) - { - this.flags = flags; - } - - /** - * @return Returns the multiRef. - */ - public boolean isMultiRef() - { - return multiRef; - } - - /** - * @param multiRef - * The multiRef to set. - */ - public void setMultiRef(boolean multiRef) - { - this.multiRef = multiRef; - } - - /** - * @return Returns the name. - */ - public String getName() - { - return name; - } - - /** - * @param name - * The name to set. - */ - public void setName(String name) - { - this.name = name; - } - - /** - * @return Returns the namespace. - */ - public String getNamespace() - { - return namespace; - } - - /** - * @param namespace - * The namespace to set. - */ - public void setNamespace(String namespace) - { - this.namespace = namespace; - } - - /** - * @return Returns the type. - */ - public Object getType() - { - return type; - } - - /** - * @param type - * The type to set. - */ - public void setType(Object type) - { - this.type = type; - } - - /** - * @return Returns the value. - */ - public Object getValue() - { - return value; - } - - /** - * @param value - * The value to set. - */ - public void setValue(Object value) - { - this.value = value; - } - - /** - * Show the name and value. - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuffer sb = new StringBuffer(); - sb.append(name); - sb.append(" : "); - if (value != null) - { - sb.append(value); - } - else - { - sb.append("(not set)"); - } - return sb.toString(); - } -} \ No newline at end of file + public static final Class OBJECT_CLASS = new Object().getClass(); + public static final Class STRING_CLASS = "".getClass(); + public static final Class INTEGER_CLASS = new Integer(0).getClass(); + public static final Class LONG_CLASS = new Long(0).getClass(); + public static final Class BOOLEAN_CLASS = new Boolean(true).getClass(); + public static final Class VECTOR_CLASS = new java.util.Vector().getClass(); + public static final PropertyInfo OBJECT_TYPE = new PropertyInfo(); + public static final int TRANSIENT = 1; + public static final int MULTI_REF = 2; + public static final int REF_ONLY = 4; + + /** + * Name of the property + */ + public String name; + + /** + * Namespace of this property + */ + public String namespace; + + /** + * Type of property, Transient, multi_ref, Ref_only *JHS* Note, not really used that effectively + */ + public int flags; + + /** + * The current value of this property. + */ + protected Object value; + + /** + * Type of the property/elements. Should usually be an instance of Class. + */ + public Object type = OBJECT_CLASS; + + /** + * if a property is multi-referenced, set this flag to true. + */ + public boolean multiRef; + + /** + * Element type for array properties, null if not array prop. + */ + public PropertyInfo elementType; + + public PropertyInfo() + { + } + + public void clear() + { + type = OBJECT_CLASS; + flags = 0; + name = null; + namespace = null; + } + + /** + * @return Returns the elementType. + */ + public PropertyInfo getElementType() + { + return elementType; + } + + /** + * @param elementType + * The elementType to set. + */ + public void setElementType(PropertyInfo elementType) + { + this.elementType = elementType; + } + + /** + * @return Returns the flags. + */ + public int getFlags() + { + return flags; + } + + /** + * @param flags + * The flags to set. + */ + public void setFlags(int flags) + { + this.flags = flags; + } + + /** + * @return Returns the multiRef. + */ + public boolean isMultiRef() + { + return multiRef; + } + + /** + * @param multiRef + * The multiRef to set. + */ + public void setMultiRef(boolean multiRef) + { + this.multiRef = multiRef; + } + + /** + * @return Returns the name. + */ + public String getName() + { + return name; + } + + /** + * @param name + * The name to set. + */ + public void setName(String name) + { + this.name = name; + } + + /** + * @return Returns the namespace. + */ + public String getNamespace() + { + return namespace; + } + + /** + * @param namespace + * The namespace to set. + */ + public void setNamespace(String namespace) + { + this.namespace = namespace; + } + + /** + * @return Returns the type. + */ + public Object getType() + { + return type; + } + + /** + * @param type + * The type to set. + */ + public void setType(Object type) + { + this.type = type; + } + + /** + * @return Returns the value. + */ + public Object getValue() + { + return value; + } + + /** + * @param value + * The value to set. + */ + public void setValue(Object value) + { + this.value = value; + } + + /** + * Show the name and value. + * + * @see java.lang.Object#toString() + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append(name); + sb.append(" : "); + if (value != null) + { + sb.append(value); + } + else + { + sb.append("(not set)"); + } + return sb.toString(); + } + + + /** + * Make a deep clone of the properties through Object serialization + * + * @see java.lang.Object#clone() + */ + public Object clone() { + Object obj = null; + try + { + // Write the object out to a byte array + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos); + out.writeObject(this); + out.flush(); + out.close(); + + // Make an input stream from the byte array and read + // a copy of the object back in. + ObjectInputStream in = new ObjectInputStream( + new ByteArrayInputStream(bos.toByteArray())); + obj = in.readObject(); + } + catch(ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + } + catch(NotSerializableException nse) + { + nse.printStackTrace(); + } + catch(IOException e) + { + e.printStackTrace(); + } + return obj; + } +} 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 2238998c..ee80f816 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapObject.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapObject.java @@ -1,22 +1,26 @@ /* * Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - * associated documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the - * following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all copies or substantial - * portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT - * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO - * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. * - * Contributor(s): John D. Beatty, Dave Dash, Andre Gerard, F. Hunter, Renaud Tognelli + * Contributor(s): John D. Beatty, Dave Dash, Andre Gerard, F. Hunter, Renaud + * Tognelli */ package org.ksoap2.serialization; @@ -24,329 +28,887 @@ import java.util.*; /** - * A simple dynamic object that can be used to build soap calls without implementing KvmSerializable - * - * Essentially, this is what goes inside the body of a soap envelope - it is the direct subelement of the body - * and all further subelements - * - * Instead of this this class, custom classes can be used if they implement the KvmSerializable interface. + * A simple dynamic object that can be used to build soap calls without + * implementing KvmSerializable + *

+ * Essentially, this is what goes inside the body of a soap envelope - it is the + * direct subelement of the body and all further subelements + *

+ * Instead of this this class, custom classes can be used if they implement the + * KvmSerializable interface. */ -public class SoapObject implements KvmSerializable -{ - /** The namespace of this soap object. */ - protected String namespace; - /** The name of this soap object. */ - protected String name; - /** The Vector of properties. */ - protected Vector properties = new Vector(); - /** The Vector of attributes. */ - protected Vector attributes = new Vector(); - - /** - * Creates a new SoapObject instance. - * - * @param namespace - * the namespace for the soap object - * @param name - * the name of the soap object - */ - - public SoapObject(String namespace, String name) - { - this.namespace = namespace; - this.name = name; - } - - public boolean equals(Object obj) - { - if (!(obj instanceof SoapObject)) - return false; - - SoapObject otherSoapObject = (SoapObject) obj; - - int numProperties = properties.size(); - if (numProperties != otherSoapObject.properties.size()) - return false; - int numAttributes = attributes.size(); - if (numAttributes != otherSoapObject.attributes.size()) - return false; - - try - { - for (int propIndex = 0; propIndex < numProperties; propIndex++) - { - PropertyInfo thisProp = (PropertyInfo) this.properties.elementAt(propIndex); - Object thisPropValue = thisProp.getValue(); - Object otherPropValue = otherSoapObject.getProperty(thisProp.getName()); - if (!thisPropValue.equals(otherPropValue)) - { - return false; - } - } - for (int attribIndex = 0; attribIndex < numAttributes; attribIndex++) - { - AttributeInfo thisAttrib = (AttributeInfo) this.properties.elementAt(attribIndex); - Object thisAttribValue = thisAttrib.getValue(); - Object otherAttribValue = otherSoapObject.getProperty(thisAttrib.getName()); - if (!thisAttribValue.equals(otherAttribValue)) - { - return false; - } - } - } - catch (Exception e) - { - return false; - } - return true; - } - - public String getName() - { - return name; - } - - public String getNamespace() - { - return namespace; - } - - /** - * Returns a specific property at a certain index. - * - * @param index - * the index of the desired property - * @return the desired property - */ - public Object getProperty(int index) - { - return ((PropertyInfo) properties.elementAt(index)).getValue(); - } - - public Object getProperty(String name) - { - for (int i = 0; i < properties.size(); i++) - { - if (name.equals(((PropertyInfo) properties.elementAt(i)).getName())) - return getProperty(i); - } - throw new RuntimeException("illegal property: " + name); - } - - /** - * Returns the number of properties - * - * @return the number of properties - */ - public int getPropertyCount() - { - return properties.size(); - } - - /** - * Places AttributeInfo of desired attribute into a designated AttributeInfo object - * - * @param index - * index of desired attribute - * @param propertyInfo - * designated retainer of desired attribute - */ - public void getAttributeInfo(int index, AttributeInfo attributeInfo) - { - AttributeInfo p = (AttributeInfo) attributes.elementAt(index); - attributeInfo.name = p.name; - attributeInfo.namespace = p.namespace; - attributeInfo.flags = p.flags; - attributeInfo.type = p.type; - attributeInfo.elementType = p.elementType; - attributeInfo.value = p.getValue(); - } - - /** - * Returns a specific attribute at a certain index. - * - * @param index - * the index of the desired attribute - * @return the value of the desired attribute - * - */ - public Object getAttribute(int index) - { - return ((AttributeInfo) attributes.elementAt(index)).getValue(); - } - - /** Returns a property with the given name. */ - public Object getAttribute(String name) - { - for (int i = 0; i < attributes.size(); i++) - { - if (name.equals(((AttributeInfo) attributes.elementAt(i)).getName())) - return getAttribute(i); - } - throw new RuntimeException("illegal property: " + name); - } - - /** - * Returns the number of attributes - * - * @return the number of attributes - */ - public int getAttributeCount() - { - return attributes.size(); - } - - /** - * Places PropertyInfo of desired property into a designated PropertyInfo object - * - * @param index - * index of desired property - * @param propertyInfo - * designated retainer of desired property - * @deprecated - */ - public void getPropertyInfo(int index, Hashtable properties, PropertyInfo propertyInfo) - { - getPropertyInfo(index, propertyInfo); - } - - /** - * Places PropertyInfo of desired property into a designated PropertyInfo object - * - * @param index - * index of desired property - * @param propertyInfo - * designated retainer of desired property - */ - public void getPropertyInfo(int index, PropertyInfo propertyInfo) - { - PropertyInfo p = (PropertyInfo) properties.elementAt(index); - propertyInfo.name = p.name; - propertyInfo.namespace = p.namespace; - propertyInfo.flags = p.flags; - propertyInfo.type = p.type; - propertyInfo.elementType = p.elementType; - } - - /** - * 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 call if the server does not send explicit type information. - * - * @return a copy of this. - */ - public SoapObject newInstance() - { - SoapObject o = new SoapObject(namespace, name); - for (int propIndex = 0; propIndex < properties.size(); propIndex++) - { - PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(propIndex); - o.addProperty(propertyInfo); - } - for (int attribIndex = 0; attribIndex < attributes.size(); attribIndex++) - { - AttributeInfo attributeInfo = (AttributeInfo) attributes.elementAt(attribIndex); - o.addAttribute(attributeInfo); - } - return o; - } - - /** - * Sets a specified property to a certain value. - * - * @param index - * the index of the specified property - * @param value - * the new value of the property - */ - public void setProperty(int index, Object value) - { - ((PropertyInfo) properties.elementAt(index)).setValue(value); - } - - /** - * Adds a property (parameter) to the object. This is essentially a sub element. - * - * @param name - * The name of the property - * @param value - * the value of the property - */ - public SoapObject addProperty(String name, Object value) - { - PropertyInfo propertyInfo = new PropertyInfo(); - propertyInfo.name = name; - 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 propertyInfo - * designated retainer of desired property - * @param value - * the value of the property - * @deprecated property info now contains the value - */ - public SoapObject addProperty(PropertyInfo propertyInfo, Object value) - { - propertyInfo.setValue(value); - addProperty(propertyInfo); - return this; - } - - /** - * Adds a property (parameter) to the object. This is essentially a sub element. - * - * @param propertyInfo - * designated retainer of desired property - */ - public SoapObject addProperty(PropertyInfo propertyInfo) - { - properties.addElement(propertyInfo); - return this; - } - - /** - * Adds a attribute (parameter) to the object. This is essentially a sub element. - * - * @param name - * The name of the attribute - * @param value - * the value of the attribute - */ - public SoapObject addAttribute(String name, Object value) - { - AttributeInfo attributeInfo = new AttributeInfo(); - attributeInfo.name = name; - attributeInfo.type = value == null ? PropertyInfo.OBJECT_CLASS : value.getClass(); - attributeInfo.value = value; - return addAttribute(attributeInfo); - } - - /** - * Adds a attribute (parameter) to the object. This is essentially a sub element. - * - * @param propertyInfo - * designated retainer of desired attribute - */ - public SoapObject addAttribute(AttributeInfo attributeInfo) - { - attributes.addElement(attributeInfo); - return this; - } - - public String toString() - { - StringBuffer buf = new StringBuffer("" + name + "{"); - for (int i = 0; i < getPropertyCount(); i++) - { - buf.append("" + ((PropertyInfo) properties.elementAt(i)).getName() + "=" + getProperty(i) + "; "); - } - buf.append("}"); - return buf.toString(); - } +public class SoapObject extends AttributeContainer implements KvmSerializable, HasInnerText { + + private static final String EMPTY_STRING = ""; + /** + * The namespace of this soap object. + */ + protected String namespace; + /** + * The name of this soap object. + */ + protected String name; + /** + * The Vector of properties (can contain PropertyInfo and SoapObject) + */ + 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 + + /** + * Creates a new SoapObject instance. + */ + + public SoapObject() { + this("",""); + } + /** + * Creates a new SoapObject instance. + * + * @param namespace + * the namespace for the soap object + * @param name + * the name of the soap object + */ + + public SoapObject(String namespace, String name) { + this.namespace = namespace; + this.name = name; + } + + public boolean equals(Object obj) { + if (!(obj instanceof SoapObject)) { + return false; + } + + SoapObject otherSoapObject = (SoapObject) obj; + + if (!name.equals(otherSoapObject.name) + || !namespace.equals(otherSoapObject.namespace)) { + return false; + } + + int numProperties = properties.size(); + if (numProperties != otherSoapObject.properties.size()) { + return false; + } + + // SoapObjects are only considered the same if properties equals and in the same order + for (int propIndex = 0; propIndex < numProperties; propIndex++) { + Object thisProp = this.properties.elementAt(propIndex); + if(!otherSoapObject.isPropertyEqual(thisProp, propIndex)) { + return false; + } + } + + return attributesAreEqual(otherSoapObject); + } + + /** + * Helper function for SoapObject.equals + * Checks if a given property and index are the same as in this + * + * @param otherProp, index + * @return + */ + public boolean isPropertyEqual(Object otherProp, int index) { + if(index >= getPropertyCount()) { + return false; + } + Object thisProp = this.properties.elementAt(index); + if(otherProp instanceof PropertyInfo && + thisProp instanceof PropertyInfo) { + // Get both PropertInfos and compare values + PropertyInfo otherPropInfo = (PropertyInfo)otherProp; + PropertyInfo thisPropInfo = (PropertyInfo)thisProp; + return otherPropInfo.getName().equals(thisPropInfo.getName()) && + otherPropInfo.getValue().equals(thisPropInfo.getValue()); + } else if (otherProp instanceof SoapObject && thisProp instanceof SoapObject) { + SoapObject otherPropSoap = (SoapObject)otherProp; + SoapObject thisPropSoap = (SoapObject)thisProp; + return otherPropSoap.equals(thisPropSoap); + } + return false; + } + + public String getName() { + return name; + } + + public String getNamespace() { + return namespace; + } + + /** + * @inheritDoc + */ + public Object getProperty(int index) { + Object prop = properties.elementAt(index); + if(prop instanceof PropertyInfo) { + return ((PropertyInfo)prop).getValue(); + } else { + return ((SoapObject)prop); + } + } + + /** + * Get the toString value of the property. + * + * @param index + * @return + */ + public String getPropertyAsString(int index) { + PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index); + return propertyInfo.getValue().toString(); + } + + /** + * Get the property with the given name + * + * @throws java.lang.RuntimeException + * if the property does not exist + */ + public Object getProperty(String name) { + Integer index = propertyIndex(name); + if (index != null) { + return getProperty(index.intValue()); + } else { + throw new RuntimeException("illegal property: " + name); + } + } + + /** + * 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. + * + * @param name + * @return + */ + + public String getPropertyAsString(String name) { + Integer index = propertyIndex(name); + if (index != null) { + return getProperty(index.intValue()).toString(); + } else { + throw new RuntimeException("illegal property: " + name); + } + } + + /** + * Knows whether the given property exists + */ + public boolean hasProperty(final String name) { + if (propertyIndex(name) != null) { + return true; + } else { + return false; + } + } + + /** + * Get a property without chance of throwing an exception + * + * @return the property if it exists; if not, {@link NullSoapObject} is + * returned + */ + public Object getPropertySafely(final String name) { + Integer i = propertyIndex(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 getPropertySafelyAsString(final String name) { + Integer i = propertyIndex(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 name, final Object defaultThing) { + Integer i = propertyIndex(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 name, + final Object defaultThing) { + Integer i = propertyIndex(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 name){ + Integer index = propertyIndex(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); + 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 name){ + Integer index = propertyIndex(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 name) { + Integer index = propertyIndex(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); + 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 name) { + Integer index = propertyIndex(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; + } + } + + + + private Integer propertyIndex(String name) { + if (name != null) { + for (int i = 0; i < properties.size(); i++) { + if (name.equals(((PropertyInfo) properties.elementAt(i)).getName())) { + return new Integer(i); + } + } + } + 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 + * + * @return the number of properties + */ + public int getPropertyCount() { + return properties.size(); + } + + /** + * Places PropertyInfo of desired property into a designated PropertyInfo + * object. Just calls #getPropertyInfo and discards any provided properties. + * + * @param index + * index of desired property + * @param properties + * this parameter is ignored + * @param propertyInfo + * designated retainer of desired property + */ + public void getPropertyInfo(int index, Hashtable properties, PropertyInfo propertyInfo) { + getPropertyInfo(index, propertyInfo); + } + + /** + * Places PropertyInfo of desired property into a designated PropertyInfo + * object + * + * @param index + * index of desired property + * @param propertyInfo + * designated retainer of desired property + */ + public void getPropertyInfo(int index, PropertyInfo propertyInfo) { + Object element = properties.elementAt(index); + if (element instanceof PropertyInfo) { + PropertyInfo p = (PropertyInfo) element; + propertyInfo.name = p.name; + propertyInfo.namespace = p.namespace; + propertyInfo.flags = p.flags; + propertyInfo.type = p.type; + propertyInfo.elementType = p.elementType; + propertyInfo.value = p.value; + propertyInfo.multiRef = p.multiRef; + } else { + // SoapObject + propertyInfo.name = null; + propertyInfo.namespace = null; + propertyInfo.flags = 0; + propertyInfo.type = null; + propertyInfo.elementType = null; + propertyInfo.value = element; + propertyInfo.multiRef = false; + } + } + + 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 + * call if the server does not send explicit type information. + * + * @return a copy of this. + */ + public SoapObject newInstance() { + SoapObject o = new SoapObject(namespace, name); + for (int propIndex = 0; propIndex < properties.size(); propIndex++) { + 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()); + } + } + for (int attribIndex = 0; attribIndex < getAttributeCount(); attribIndex++) { + AttributeInfo newAI = new AttributeInfo(); + getAttributeInfo(attribIndex, newAI); + AttributeInfo attributeInfo = newAI; // (AttributeInfo) + // attributes.elementAt(attribIndex); + o.addAttribute(attributeInfo); + } + return o; + } + + /** + * Sets a specified property to a certain value. + * + * @param index + * the index of the specified property + * @param value + * the new value of the property + */ + public void setProperty(int index, Object value) { + Object prop = properties.elementAt(index); + if(prop instanceof PropertyInfo) { + ((PropertyInfo) prop).setValue(value); + } + // TODO: not sure how you want to handle an exception here if the index points to a SoapObject + } + + /** + * Adds a property (parameter) to the object. This is essentially a sub + * element. + * + * @param name + * The name of the property + * @param value + * the value of the property + */ + public SoapObject addProperty(String name, Object value) { + PropertyInfo propertyInfo = new PropertyInfo(); + propertyInfo.name = name; + 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; + 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. + * + * @param name + * @param value + * @return + */ + public SoapObject addPropertyIfValue(String name, Object value) { + if (value != null) { + return addProperty(name, value); + } else { + return this; + } + } + + /** + * Add a property only if the value is not null. + * + * @param propertyInfo + * @param value + * @return + */ + public SoapObject addPropertyIfValue(PropertyInfo propertyInfo, Object value) { + if (value != null) { + propertyInfo.setValue(value); + return addProperty(propertyInfo); + } else { + return this; + } + } + + /** + * Adds a property (parameter) to the object. This is essentially a sub + * element. + * + * @param propertyInfo + * designated retainer of desired property + */ + public SoapObject addProperty(PropertyInfo propertyInfo) { + properties.addElement(propertyInfo); + return this; + } + + /** + * Ad the propertyInfo only if the value of it is not null. + * + * @param propertyInfo + * @return + */ + public SoapObject addPropertyIfValue(PropertyInfo propertyInfo) { + if (propertyInfo.value != null) { + properties.addElement(propertyInfo); + return this; + } else { + return this; + } + } + + /** + * Adds a SoapObject the properties array. This is a sub element to + * allow nested SoapObjects + * + * @param soapObject + * to be added as a property of the current object + */ + public SoapObject addSoapObject(SoapObject soapObject) { + properties.addElement(soapObject); + return this; + } + + /** + * Generate a {@code String} describing this object. + * + * @return + */ + public String toString() { + StringBuffer buf = new StringBuffer(EMPTY_STRING + name + "{"); + for (int i = 0; i < getPropertyCount(); i++) { + Object prop = properties.elementAt(i); + if(prop instanceof PropertyInfo) { + buf.append(EMPTY_STRING) + .append(((PropertyInfo) prop).getName()) + .append("=") + .append(getProperty(i)) + .append("; "); + } else { + buf.append(((SoapObject) prop).toString()); + } + } + 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 1f7b6e88..eda399cb 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapPrimitive.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapPrimitive.java @@ -23,7 +23,7 @@ /** * A class that is used to encapsulate primitive types (represented by a string * in XML serialization). - * + * * Basically, the SoapPrimitive class encapsulates "unknown" primitive types * (similar to SoapObject encapsulating unknown complex types). For example, new * SoapPrimitive (classMap.xsd, "float", "12.3") allows you to send a float from @@ -33,12 +33,15 @@ * namespace, name and string value (this is how the stockquote example works). */ -public class SoapPrimitive { - String namespace; - String name; - String value; +public class SoapPrimitive extends AttributeContainer { + protected String namespace; + protected String name; + protected Object value; + + public static final Object NullSkip = new Object(); + public static final Object NullNilElement = new Object(); - public SoapPrimitive(String namespace, String name, String value) { + public SoapPrimitive(String namespace, String name, Object value) { this.namespace = namespace; this.name = name; this.value = value; @@ -49,7 +52,10 @@ public boolean equals(Object o) { return false; } SoapPrimitive p = (SoapPrimitive) o; - return name.equals(p.name) && (namespace == null ? p.namespace == null:namespace.equals(p.namespace)) && (value == null ? (p.value == null) : value.equals(p.value)); + boolean varsEqual = name.equals(p.name) + && (namespace == null ? p.namespace == null:namespace.equals(p.namespace)) + && (value == null ? (p.value == null) : value.equals(p.value)); + return varsEqual && attributesAreEqual(p); } public int hashCode() { @@ -57,7 +63,7 @@ public int hashCode() { } public String toString() { - return value; + return value != null ? value.toString() : null; } public String getNamespace() { @@ -68,4 +74,8 @@ 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 5c5219bc..653c55fd 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapSerializationEnvelope.java +++ b/ksoap2-base/src/main/java/org/ksoap2/serialization/SoapSerializationEnvelope.java @@ -1,15 +1,15 @@ /* * Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the * following conditions: - * + * * The above copyright notice and this permission notice shall be included in all copies or substantial * portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER @@ -19,643 +19,872 @@ package org.ksoap2.serialization; -import java.io.*; -import java.util.*; +import org.ksoap2.SoapEnvelope; +import org.ksoap2.SoapFault; +import org.ksoap2.SoapFault12; +import org.xmlpull.v1.XmlPullParser; +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 org.ksoap2.*; -import org.xmlpull.v1.*; /** * @author Stefan Haustein - * + *

* This class extends the SoapEnvelope with Soap Serialization functionality. */ -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; - 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(); - - public boolean implicitTypes; - - /** - * 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 - * configuration of the .Net-Server to standard Soap Serialization! - */ - - public boolean dotNet; - - /** - * Map from XML qualified names to Java classes - */ - - protected Hashtable qNameToClass = new Hashtable(); - - /** - * Map from Java class names to XML name and namespace pairs - */ - - protected Hashtable classToQName = new Hashtable(); - - /** - * Set to true to add and ID and ROOT label to the envelope. Change to false for compatibility with WSDL. - */ - protected boolean addAdornments = true; - - public SoapSerializationEnvelope(int version) - { - super(version); - addMapping(enc, ARRAY_MAPPING_NAME, PropertyInfo.VECTOR_CLASS); - DEFAULT_MARSHAL.register(this); - } - - /** - * @return the addAdornments - */ - public boolean isAddAdornments() - { - return addAdornments; - } - - /** - * @param addAdornments - * the addAdornments to set - */ - public void setAddAdornments(boolean addAdornments) - { - this.addAdornments = addAdornments; - } - - public void parseBody(XmlPullParser parser) throws IOException, XmlPullParserException - { - bodyIn = null; - parser.nextTag(); - if (parser.getEventType() == XmlPullParser.START_TAG && parser.getNamespace().equals(env) - && parser.getName().equals("Fault")) - { - SoapFault fault = new SoapFault(); - fault.parse(parser); - bodyIn = fault; - } - else - { - while (parser.getEventType() == XmlPullParser.START_TAG) - { - String rootAttr = parser.getAttributeValue(enc, ROOT_LABEL); - Object o = read(parser, null, -1, parser.getNamespace(), parser.getName(), - PropertyInfo.OBJECT_TYPE); - if ("1".equals(rootAttr) || bodyIn == null) - bodyIn = o; - parser.nextTag(); - } - } - } - - /** 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 - { - for (int counter = 0; counter < parser.getAttributeCount(); counter++) - { - String attributeName = parser.getAttributeName(counter); - String value = parser.getAttributeValue(counter); - ((SoapObject) obj).addAttribute(attributeName, value); - } - readSerializable(parser, (KvmSerializable) obj); - } - - /** Read a KvmSerializable. */ - protected void readSerializable(XmlPullParser parser, KvmSerializable obj) throws IOException, - XmlPullParserException - { - int testIndex = -1; // inc at beg. of loop for perf. reasons - int propertyCount = obj.getPropertyCount(); - PropertyInfo info = new PropertyInfo(); - while (parser.nextTag() != XmlPullParser.END_TAG) - { - String name = parser.getName(); - int countdown = propertyCount; - // I don't really understand what's going on in this "while(true)" - // clause. The structure surely is wrong "while(true)" with a break is - // pretty much always because the person who wrote it couldn't figure out what - // it was really supposed to be doing. - // So, here's a little CYA since I think the code is only broken for - // implicitTypes - if (!implicitTypes || !(obj instanceof SoapObject)) - { - while (true) - { - if (countdown-- == 0) - { - throw new RuntimeException("Unknown Property: " + name); - } - if (++testIndex >= propertyCount) - { - testIndex = 0; - } - obj.getPropertyInfo(testIndex, properties, info); - if (info.namespace == null && name.equals(info.name) || info.name == null - && testIndex == 0 || name.equals(info.name) - && parser.getNamespace().equals(info.namespace)) - { - break; - } - } - obj.setProperty(testIndex, read(parser, obj, testIndex, null, null, info)); - } - 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)); - } - } - parser.require(XmlPullParser.END_TAG, null, null); - } - - /** - * If the type of the object cannot be determined, and thus no Marshal class can handle the object, this - * method is called. It will build either a SoapPrimitive or a SoapObject - * - * @param parser - * @param typeNamespace - * @param typeName - * @return unknownObject wrapped as a SoapPrimitive or SoapObject - * @throws IOException - * @throws XmlPullParserException - */ - - protected Object readUnknown(XmlPullParser parser, String typeNamespace, String typeName) - throws IOException, XmlPullParserException - { - String name = parser.getName(); - String namespace = parser.getNamespace(); - parser.next(); // move to text, inner start tag or end tag - Object result = null; - String text = null; - if (parser.getEventType() == XmlPullParser.TEXT) - { - text = parser.getText(); - result = new SoapPrimitive(typeNamespace, typeName, text); - parser.next(); - } - else if (parser.getEventType() == XmlPullParser.END_TAG) - { - result = new SoapObject(typeNamespace, typeName); - } - - if (parser.getEventType() == XmlPullParser.START_TAG) - { - if (text != null && text.trim().length() != 0) - { - throw new RuntimeException("Malformed input: Mixed content"); - } - SoapObject so = new SoapObject(typeNamespace, typeName); - while (parser.getEventType() != XmlPullParser.END_TAG) - { - so.addProperty(parser.getName(), read(parser, so, so.getPropertyCount(), null, null, - PropertyInfo.OBJECT_TYPE)); - parser.nextTag(); - } - result = so; - } - parser.require(XmlPullParser.END_TAG, namespace, name); - return result; - } - - private int getIndex(String value, int start, int dflt) - { - if (value == null) - return dflt; - return value.length() - start < 3 ? dflt : Integer.parseInt(value.substring(start + 1, - value.length() - 1)); - } - - protected void readVector(XmlPullParser parser, Vector v, PropertyInfo elementType) throws IOException, - XmlPullParserException - { - String namespace = null; - String name = null; - int size = v.size(); - boolean dynamic = true; - String type = parser.getAttributeValue(enc, ARRAY_TYPE_LABEL); - if (type != null) - { - int cut0 = type.indexOf(':'); - int cut1 = type.indexOf("[", cut0); - name = type.substring(cut0 + 1, cut1); - String prefix = cut0 == -1 ? "" : type.substring(0, cut0); - namespace = parser.getNamespace(prefix); - size = getIndex(type, cut1, -1); - if (size != -1) - { - v.setSize(size); - dynamic = false; - } - } - if (elementType == null) - elementType = PropertyInfo.OBJECT_TYPE; - parser.nextTag(); - int position = getIndex(parser.getAttributeValue(enc, "offset"), 0, 0); - while (parser.getEventType() != XmlPullParser.END_TAG) - { - // handle position - position = getIndex(parser.getAttributeValue(enc, "position"), 0, position); - if (dynamic && position >= size) - { - size = position + 1; - v.setSize(size); - } - // implicit handling of position exceeding specified size - v.setElementAt(read(parser, v, position, namespace, name, elementType), position); - position++; - parser.nextTag(); - } - parser.require(XmlPullParser.END_TAG, null, null); - } - - /** - * 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 - { - String elementName = parser.getName(); - String href = parser.getAttributeValue(null, HREF_LABEL); - Object obj; - if (href != null) - { - if (owner == null) - throw new RuntimeException("href at root level?!?"); - href = href.substring(1); - obj = idMap.get(href); - if (obj == null || obj instanceof FwdRef) - { - FwdRef f = new FwdRef(); - f.next = (FwdRef) obj; - f.obj = owner; - f.index = index; - idMap.put(href, f); - obj = null; - } - parser.nextTag(); // start tag - parser.require(XmlPullParser.END_TAG, null, elementName); - } - else - { - String nullAttr = parser.getAttributeValue(xsi, NIL_LABEL); - String id = parser.getAttributeValue(null, ID_LABEL); - if (nullAttr == null) - nullAttr = parser.getAttributeValue(xsi, NULL_LABEL); - if (nullAttr != null && SoapEnvelope.stringToBoolean(nullAttr)) - { - obj = null; - parser.nextTag(); - parser.require(XmlPullParser.END_TAG, null, elementName); - } - else - { - String type = parser.getAttributeValue(xsi, TYPE_LABEL); - if (type != null) - { - int cut = type.indexOf(':'); - name = type.substring(cut + 1); - String prefix = cut == -1 ? "" : type.substring(0, cut); - namespace = parser.getNamespace(prefix); - } - else if (name == null && namespace == null) - { - if (parser.getAttributeValue(enc, ARRAY_TYPE_LABEL) != null) - { - namespace = enc; - name = ARRAY_MAPPING_NAME; - } - else - { - Object[] names = getInfo(expected.type, null); - namespace = (String) names[0]; - name = (String) names[1]; - } - } - // be sure to set this flag if we don't know the types. - if (type == null) - { - implicitTypes = true; - } - obj = readInstance(parser, namespace, name, expected); - if (obj == null) - obj = readUnknown(parser, namespace, name); - } - // 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); - } - } - - parser.require(XmlPullParser.END_TAG, null, elementName); - return 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) - throws IOException, XmlPullParserException - { - Object obj = qNameToClass.get(new SoapPrimitive(namespace, name, null)); - if (obj == null) - return null; - if (obj instanceof Marshal) - return ((Marshal) obj).readInstance(parser, namespace, name, expected); - else if (obj instanceof SoapObject) - { - obj = ((SoapObject) obj).newInstance(); - } - else if (obj == SoapObject.class) - { - obj = new SoapObject(namespace, name); - } - else - { - try - { - obj = ((Class) obj).newInstance(); - } - catch (Exception e) - { - throw new RuntimeException(e.toString()); - } - } - // ok, obj is now the instance, fill it.... - if (obj instanceof SoapObject) - readSerializable(parser, (SoapObject) obj); - else if (obj instanceof KvmSerializable) - readSerializable(parser, (KvmSerializable) obj); - else if (obj instanceof Vector) - readVector(parser, (Vector) obj, expected.elementType); - else - throw new RuntimeException("no deserializer for " + obj.getClass()); - return obj; - } - - /** - * Returns a string array containing the namespace, name, id and Marshal object for the given java object. - * This method is used by the SoapWriter in order to map Java objects to the corresponding SOAP section - * five XML code. - */ - public Object[] getInfo(Object type, Object instance) - { - if (type == null) - { - if (instance instanceof SoapObject || instance instanceof SoapPrimitive) - type = instance; - else - type = instance.getClass(); - } - if (type instanceof SoapObject) - { - SoapObject so = (SoapObject) type; - 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 }; - } - if ((type instanceof Class) && type != PropertyInfo.OBJECT_CLASS) - { - Object[] tmp = (Object[]) classToQName.get(((Class) type).getName()); - if (tmp != null) - return tmp; - } - return new Object[] { xsd, ANY_TYPE_LABEL, null, null }; - } - - /** - * Defines a direct mapping from a namespace and name to a java class (and vice versa), using the given - * marshal mechanism - */ - 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 }); - } - - /** - * Defines a direct mapping from a namespace and name to a java class (and vice versa) - */ - public void addMapping(String namespace, String name, Class clazz) - { - addMapping(namespace, name, clazz, null); - } - - /** - * Adds a SoapObject to the class map. During parsing, objects of the given type (namespace/name) will be - * mapped to corresponding copies of the given SoapObject, maintaining the structure of the template. - */ - public void addTemplate(SoapObject so) - { - qNameToClass.put(new SoapPrimitive(so.namespace, so.name, null), so); - } - - /** - * 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 - */ - public Object getResponse() throws SoapFault - { - if (bodyIn instanceof SoapFault) - { - throw (SoapFault) bodyIn; - } - KvmSerializable ks = (KvmSerializable) bodyIn; - return ks.getPropertyCount() == 0 ? null : ks.getProperty(0); - } - - /** - * @deprecated Please use the getResponse going forward - * @see #getResponse() - */ - public Object getResult() - { - KvmSerializable ks = (KvmSerializable) bodyIn; - return ks.getPropertyCount() == 0 ? null : ks.getProperty(0); - } - - /** - * Serializes the request object to the given XmlSerliazer object - * - * @param writer - * XmlSerializer object to write the body into. - */ - public void writeBody(XmlSerializer writer) throws IOException - { - multiRef = new Vector(); - multiRef.addElement(bodyOut); - Object[] qName = getInfo(null, bodyOut); - 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]); - - } - - /** - * 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; - for (int counter = 0; counter < soapObject.getAttributeCount(); counter++) - { - AttributeInfo attributeInfo = new AttributeInfo(); - soapObject.getAttributeInfo(counter, attributeInfo); - writer.attribute(attributeInfo.getNamespace(), attributeInfo.getName(), attributeInfo.getValue() - .toString()); - } - writeObjectBody(writer, (KvmSerializable) obj); - } - - /** - * Writes the body of an KvmSerializable object. This method is public for access from Marshal subclasses. - */ - public void writeObjectBody(XmlSerializer writer, KvmSerializable obj) throws IOException - { - PropertyInfo info = new PropertyInfo(); - int cnt = obj.getPropertyCount(); - for (int i = 0; i < cnt; i++) - { - obj.getPropertyInfo(i, properties, info); - if ((info.flags & PropertyInfo.TRANSIENT) == 0) - { - writer.startTag(info.namespace, info.name); - writeProperty(writer, obj.getProperty(i), info); - writer.endTag(info.namespace, info.name); - } - } - } - - protected void writeProperty(XmlSerializer writer, Object obj, PropertyInfo type) throws IOException - { - if (obj == null) - { - writer.attribute(xsi, version >= VER12 ? NIL_LABEL : NULL_LABEL, "true"); - return; - } - Object[] qName = getInfo(null, obj); - if (type.multiRef || qName[2] != null) - { - int i = multiRef.indexOf(obj); - if (i == -1) - { - i = multiRef.size(); - multiRef.addElement(obj); - } - writer.attribute(null, HREF_LABEL, qName[2] == null ? ("#o" + i) : "#" + qName[2]); - } - else - { - if (!implicitTypes || obj.getClass() != type.type) - { - String prefix = writer.getPrefix((String) qName[QNAME_NAMESPACE], true); - writer.attribute(xsi, TYPE_LABEL, prefix + ":" + qName[QNAME_TYPE]); - } - writeElement(writer, obj, type, qName[QNAME_MARSHAL]); - } - } - - private 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 Vector) - writeVectorBody(writer, (Vector) element, type.elementType); - else - throw new RuntimeException("Cannot serialize: " + element); - } - - protected void writeVectorBody(XmlSerializer writer, Vector vector, PropertyInfo elementType) - throws IOException - { - if (elementType == null) - elementType = PropertyInfo.OBJECT_TYPE; - int cnt = vector.size(); - Object[] arrType = getInfo(elementType.type, null); - // I think that this needs an implicitTypes check, but don't have a failure case for that - writer.attribute(enc, ARRAY_TYPE_LABEL, writer.getPrefix((String) arrType[0], false) + ":" - + arrType[1] + "[" + cnt + "]"); - boolean skipped = false; - for (int i = 0; i < cnt; i++) - { - if (vector.elementAt(i) == null) - skipped = true; - else - { - writer.startTag(null, ITEM_LABEL); - if (skipped) - { - writer.attribute(enc, "position", "[" + i + "]"); - skipped = false; - } - writeProperty(writer, vector.elementAt(i), elementType); - writer.endTag(null, ITEM_LABEL); - } - } - } - +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 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"; + public Hashtable properties = new Hashtable(); + /** + * 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 + */ + 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 + * configuration of the .Net-Server to standard Soap Serialization! + */ + + public boolean dotNet; + /** + * Set this variable to true if you prefer to silently skip unknown properties. + * {@link RuntimeException} will be thrown otherwise. + */ + public boolean avoidExceptionForUnknownProperty; + /** + * Map from XML qualified names to Java classes + */ + + protected Hashtable qNameToClass = new Hashtable(); + /** + * Map from Java class names to XML name and namespace pairs + */ + + protected Hashtable classToQName = new Hashtable(); + /** + * 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) { + super(version); + addMapping(enc, ARRAY_MAPPING_NAME, PropertyInfo.VECTOR_CLASS); + DEFAULT_MARSHAL.register(this); + } + + /** + * @return the addAdornments + */ + public boolean isAddAdornments() { + return addAdornments; + } + + /** + * @param addAdornments the addAdornments to set + */ + 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" + */ + public void setBodyOutEmpty(boolean emptyBody) { + if (emptyBody) { + bodyOut = null; + } + } + + public void parseBody(XmlPullParser parser) throws IOException, XmlPullParserException { + bodyIn = null; + parser.nextTag(); + if (parser.getEventType() == XmlPullParser.START_TAG && parser.getNamespace().equals(env) + && parser.getName().equals("Fault")) { + SoapFault fault; + if (this.version < SoapEnvelope.VER12) { + fault = new SoapFault(this.version); + } else { + fault = new SoapFault12(this.version); + } + fault.parse(parser); + bodyIn = fault; + } else { + while (parser.getEventType() == XmlPullParser.START_TAG) { + String rootAttr = parser.getAttributeValue(enc, ROOT_LABEL); + + Object o = read(parser, null, -1, parser.getNamespace(), parser.getName(), + PropertyInfo.OBJECT_TYPE); + if ("1".equals(rootAttr) || bodyIn == null) { + bodyIn = o; + } + parser.nextTag(); + } + } + } + + /** + * 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 { + for (int counter = 0; counter < parser.getAttributeCount(); counter++) { + String attributeName = parser.getAttributeName(counter); + String value = parser.getAttributeValue(counter); + ((SoapObject) obj).addAttribute(attributeName, value); + } + readSerializable(parser, (KvmSerializable) obj); + } + + /** + * Read a KvmSerializable. + */ + protected void readSerializable(XmlPullParser parser, KvmSerializable obj) throws IOException, + 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(); + int propertyCount = obj.getPropertyCount(); + boolean propertyFound = false; + + for (int i = 0; i < propertyCount && !propertyFound; i++) { + info.clear(); + obj.getPropertyInfo(i, properties, info); + + 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)); + } + } + + if (!propertyFound) { + if (avoidExceptionForUnknownProperty) { + // Dummy loop to read until corresponding END tag + 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)); + } + 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); + } + + /** + * If the type of the object cannot be determined, and thus no Marshal class can handle the object, this + * method is called. It will build either a SoapPrimitive or a SoapObject + * + * @param parser + * @param typeNamespace + * @param typeName + * @return unknownObject wrapped as a SoapPrimitive or SoapObject + * @throws IOException + * @throws XmlPullParserException + */ + + protected Object readUnknown(XmlPullParser parser, String typeNamespace, String typeName) + throws IOException, XmlPullParserException { + String name = parser.getName(); + String namespace = parser.getNamespace(); + + // cache the attribute info list from the current element before we move on + Vector attributeInfoVector = new Vector(); + for (int attributeCount = 0; attributeCount < parser.getAttributeCount(); attributeCount++) { + AttributeInfo attributeInfo = new AttributeInfo(); + attributeInfo.setName(parser.getAttributeName(attributeCount)); + attributeInfo.setValue(parser.getAttributeValue(attributeCount)); + attributeInfo.setNamespace(parser.getAttributeNamespace(attributeCount)); + attributeInfo.setType(parser.getAttributeType(attributeCount)); + attributeInfoVector.addElement(attributeInfo); + } + + parser.next(); // move to text, inner start tag or end tag + Object result = null; + String text = null; + if (parser.getEventType() == XmlPullParser.TEXT) { + text = parser.getText(); + SoapPrimitive sp = new SoapPrimitive(typeNamespace, typeName, text); + result = sp; + // apply all the cached attribute info list before we add the property and descend further for parsing + for (int i = 0; i < attributeInfoVector.size(); i++) { + sp.addAttribute((AttributeInfo) attributeInfoVector.elementAt(i)); + } + parser.next(); + } else if (parser.getEventType() == XmlPullParser.END_TAG) { + SoapObject so = new SoapObject(typeNamespace, typeName); + // apply all the cached attribute info list before we add the property and descend further for parsing + for (int i = 0; i < attributeInfoVector.size(); i++) { + so.addAttribute((AttributeInfo) attributeInfoVector.elementAt(i)); + } + result = so; + } + + if (parser.getEventType() == XmlPullParser.START_TAG) { + if (text != null && text.trim().length() != 0) { + throw new RuntimeException("Malformed input: Mixed content"); + } + SoapObject so = new SoapObject(typeNamespace, typeName); + // apply all the cached attribute info list before we add the property and descend further for parsing + for (int i = 0; i < attributeInfoVector.size(); i++) { + so.addAttribute((AttributeInfo) attributeInfoVector.elementAt(i)); + } + + while (parser.getEventType() != XmlPullParser.END_TAG) { + so.addProperty(parser.getNamespace(),parser.getName(), read(parser, so, so.getPropertyCount(), + null, null, PropertyInfo.OBJECT_TYPE)); + parser.nextTag(); + } + result = so; + } + parser.require(XmlPullParser.END_TAG, namespace, name); + return result; + } + + private int getIndex(String value, int start, int dflt) { + if (value == null) { + return dflt; + } + 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, + XmlPullParserException { + String namespace = null; + String name = null; + int size = v.size(); + boolean dynamic = true; + String type = parser.getAttributeValue(enc, ARRAY_TYPE_LABEL); + if (type != null) { + int cut0 = type.indexOf(':'); + int cut1 = type.indexOf("[", cut0); + name = type.substring(cut0 + 1, cut1); + String prefix = cut0 == -1 ? "" : type.substring(0, cut0); + namespace = parser.getNamespace(prefix); + size = getIndex(type, cut1, -1); + if (size != -1) { + v.setSize(size); + dynamic = false; + } + } + if (elementType == null) { + elementType = PropertyInfo.OBJECT_TYPE; + } + parser.nextTag(); + int position = getIndex(parser.getAttributeValue(enc, "offset"), 0, 0); + while (parser.getEventType() != XmlPullParser.END_TAG) { + // handle position + position = getIndex(parser.getAttributeValue(enc, "position"), 0, position); + if (dynamic && position >= size) { + size = position + 1; + v.setSize(size); + } + // implicit handling of position exceeding specified size + v.setElementAt(read(parser, v, position, namespace, name, elementType), position); + position++; + parser.nextTag(); + } + 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 { + String elementName = parser.getName(); + String href = parser.getAttributeValue(null, HREF_LABEL); + Object obj; + if (href != null) { + if (owner == null) { + throw new RuntimeException("href at root level?!?"); + } + href = getIdFromHref(href); + obj = idMap.get(href); + if (obj == null || obj instanceof FwdRef) { + FwdRef f = new FwdRef(); + f.next = (FwdRef) obj; + f.obj = owner; + f.index = index; + idMap.put(href, f); + obj = null; + } + parser.nextTag(); // start tag + parser.require(XmlPullParser.END_TAG, null, elementName); + } else { + String nullAttr = parser.getAttributeValue(xsi, NIL_LABEL); + String id = parser.getAttributeValue(null, ID_LABEL); + if (nullAttr == null) { + nullAttr = parser.getAttributeValue(xsi, NULL_LABEL); + } + if (nullAttr != null && SoapEnvelope.stringToBoolean(nullAttr)) { + obj = null; + parser.nextTag(); + parser.require(XmlPullParser.END_TAG, null, elementName); + } else { + String type = parser.getAttributeValue(xsi, TYPE_LABEL); + if (type != null) { + int cut = type.indexOf(':'); + name = type.substring(cut + 1); + String prefix = cut == -1 ? "" : type.substring(0, cut); + namespace = parser.getNamespace(prefix); + } else if (name == null && namespace == null) { + if (parser.getAttributeValue(enc, ARRAY_TYPE_LABEL) != null) { + namespace = enc; + name = ARRAY_MAPPING_NAME; + } else { + Object[] names = getInfo(expected.type, null); + namespace = (String) names[0]; + name = (String) names[1]; + } + } + // be sure to set this flag if we don't know the types. + if (type == null) { + implicitTypes = true; + } + obj = readInstance(parser, namespace, name, expected); + if (obj == null) { + obj = readUnknown(parser, namespace, name); + } + } + // finally, care about the id.... + if (id != null) { + resolveReference(id, obj); + + } + } + + parser.require(XmlPullParser.END_TAG, null, elementName); + 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) + throws IOException, XmlPullParserException { + Object obj = qNameToClass.get(new SoapPrimitive(namespace, name, null)); + if (obj == null) { + return null; + } + if (obj instanceof Marshal) { + return ((Marshal) obj).readInstance(parser, namespace, name, expected); + } else if (obj instanceof SoapObject) { + obj = ((SoapObject) obj).newInstance(); + } else if (obj == SoapObject.class) { + obj = new SoapObject(namespace, name); + } else { + try { + obj = ((Class) obj).newInstance(); + } catch (Exception e) { + 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); + + } else { + throw new RuntimeException("no deserializer for " + obj.getClass()); + } + + return obj; + } + + /** + * Returns a string array containing the namespace, name, id and Marshal object for the given java object. + * This method is used by the SoapWriter in order to map Java objects to the corresponding SOAP section + * five XML code. + */ + public Object[] getInfo(Object type, Object instance) { + if (type == null) { + if (instance instanceof SoapObject || instance instanceof SoapPrimitive) { + type = instance; + } else { + type = instance.getClass(); + } + } + if (type instanceof SoapObject) { + SoapObject so = (SoapObject) type; + 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}; + } + if ((type instanceof Class) && type != PropertyInfo.OBJECT_CLASS) { + Object[] tmp = (Object[]) classToQName.get(((Class) type).getName()); + if (tmp != null) { + return tmp; + } + } + return new Object[]{xsd, ANY_TYPE_LABEL, null, null}; + } + + /** + * Defines a direct mapping from a namespace and name to a java class (and vice versa), using the given + * marshal mechanism + */ + 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}); + } + + /** + * Defines a direct mapping from a namespace and name to a java class (and vice versa) + */ + public void addMapping(String namespace, String name, Class clazz) { + addMapping(namespace, name, clazz, null); + } + + /** + * Adds a SoapObject to the class map. During parsing, objects of the given type (namespace/name) will be + * mapped to corresponding copies of the given SoapObject, maintaining the structure of the template. + */ + public void addTemplate(SoapObject so) { + qNameToClass.put(new SoapPrimitive(so.namespace, so.name, null), so); + } + + /** + * Response from the soap call. Pulls the object from the wrapper object and returns it. + * + * @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; + } + KvmSerializable ks = (KvmSerializable) bodyIn; + + if (ks.getPropertyCount() == 0) { + return null; + } else if (ks.getPropertyCount() == 1) { + return ks.getProperty(0); + } else { + Vector ret = new Vector(); + for (int i = 0; i < ks.getPropertyCount(); i++) { + ret.add(ks.getProperty(i)); + } + return ret; + } + } + + /** + * Serializes the request object to the given XmlSerliazer object + * + * @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 + // see http://code.google.com/p/ksoap2-android/issues/detail?id=77 + if (bodyOut != null) { + multiRef = new Vector(); + multiRef.addElement(bodyOut); + Object[] qName = getInfo(null, bodyOut); + + 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]); + } + } + + 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); + 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); + } + writeArrayListBody(writer, (ArrayList) obj); + } + + public void writeObjectBodyWithAttributes(XmlSerializer writer, KvmSerializable obj) throws IOException { + if (obj instanceof HasAttributes) { + writeAttributes(writer, (HasAttributes) obj); + } + writeObjectBody(writer, obj); + } + + /** + * Writes the body of an KvmSerializable object. This method is public for access from Marshal subclasses. + */ + public void writeObjectBody(XmlSerializer writer, KvmSerializable obj) throws IOException { + int cnt = obj.getPropertyCount(); + 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); + + } + + 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.cdsect(value.toString()); + } + + } + } + } + + 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); + if (type.multiRef || qName[2] != null) { + int i = multiRef.indexOf(obj); + if (i == -1) { + i = multiRef.size(); + multiRef.addElement(obj); + } + writer.attribute(null, HREF_LABEL, qName[2] == null ? ("#o" + i) : "#" + qName[2]); + } else { + if (!implicitTypes || obj.getClass() != type.type) { + String prefix = writer.getPrefix((String) qName[QNAME_NAMESPACE], true); + writer.attribute(xsi, TYPE_LABEL, prefix + ":" + qName[QNAME_TYPE]); + } + writeElement(writer, obj, type, qName[QNAME_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 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 { + throw new RuntimeException("Cannot serialize: " + element); + } + } + + 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; + String itemsNamespace = null; + + if (elementType == null) { + elementType = PropertyInfo.OBJECT_TYPE; + } else if (elementType instanceof PropertyInfo) { + if (elementType.name != null) { + itemsTagName = elementType.name; + itemsNamespace = elementType.namespace; + } + } + + int cnt = vector.size(); + Object[] arrType = getInfo(elementType.type, null); + + // 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) + ":" + + 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; + for (int i = 0; i < cnt; i++) { + if (vector.elementAt(i) == null) { + skipped = true; + } else { + writer.startTag(itemsNamespace, itemsTagName); + if (skipped) { + writer.attribute(enc, "position", "[" + i + "]"); + skipped = false; + } + writeProperty(writer, vector.elementAt(i), elementType); + writer.endTag(itemsNamespace, itemsTagName); + } + } + } } 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 00000000..fdbaa21a --- /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 2bbf6d5e..d30e4d13 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/transport/ServiceConnection.java +++ b/ksoap2-base/src/main/java/org/ksoap2/transport/ServiceConnection.java @@ -21,13 +21,19 @@ package org.ksoap2.transport; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; /** * Interface to allow the abstraction of the raw transport information */ public interface ServiceConnection { + public static final int DEFAULT_TIMEOUT = 20000; // 20 seconds + public static final int DEFAULT_BUFFER_SIZE = 256*1024; // 256 Kb + /** * Make an outgoing connection. * @@ -42,6 +48,25 @@ public interface ServiceConnection { */ public void disconnect() throws IOException; + /** + * Returns to the caller all of the headers that were returned with the + * response to the SOAP request. Primarily this gives the caller an + * opportunity to save the cookies for later use. + * + * @return List of HeaderProperty instances that were returned as part of the http response as http header + * properties + * + * @exception IOException + */ + 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. * @@ -63,6 +88,17 @@ public interface ServiceConnection { */ public void setRequestMethod(String requestMethodType) throws IOException; + /** + * If the length of a HTTP request body is known ahead, sets fixed length + * to enable streaming without buffering. Sets after connection will cause an exception. + * + * @param contentLength the fixed length of the HTTP request body + * @see http://developer.android.com/reference/java/net/HttpURLConnection.html + **/ + public void setFixedLengthStreamingMode(int contentLength); + + public void setChunkedStreamingMode(); + /** * Open and return the outputStream to the endpoint. * @@ -86,4 +122,24 @@ public interface ServiceConnection { */ public InputStream getErrorStream(); + /** + * Return the name of the host that is specified as the web service target + * + * @return Host name + */ + abstract public String getHost(); + + /** + * Return the port number of the host that is specified as the web service target + * + * @return Port number + */ + abstract public int getPort(); + + /** + * Return the path to the web service target + * + * @return The URL's path + */ + abstract public String getPath(); } 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 2821b33a..5bc5d50f 100644 --- a/ksoap2-base/src/main/java/org/ksoap2/transport/Transport.java +++ b/ksoap2-base/src/main/java/org/ksoap2/transport/Transport.java @@ -23,7 +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.*; @@ -37,7 +43,15 @@ */ 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. + */ + protected Proxy proxy; protected String url; + protected int timeout = ServiceConnection.DEFAULT_TIMEOUT; + protected int readTimeout = ServiceConnection.DEFAULT_TIMEOUT; /** Set to true if debugging */ public boolean debug; /** String dump of request for debugging. */ @@ -46,37 +60,121 @@ abstract public class Transport { public String responseDump; private String xmlVersionTag = ""; + protected static final String CONTENT_TYPE_XML_CHARSET_UTF_8 = "text/xml;charset=utf-8"; + protected static final String CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8 = "application/soap+xml;charset=utf-8"; + protected static final String USER_AGENT = "ksoap2-android/2.6.0+;version=3.6.4"; + + private int bufferLength = ServiceConnection.DEFAULT_BUFFER_SIZE; + + private HashMap prefixes = new HashMap(); + + public HashMap getPrefixes() { + return prefixes; + } + + public void setReadTimeout(int readTimeout){ + this.readTimeout = readTimeout; + } + public Transport() { } public Transport(String url) { + this(null, url); + } + + public Transport(String url, int timeout) { this.url = url; + this.timeout = timeout; + } + + public Transport(String url, int timeout, int bufferLength) { + this.url = url; + this.timeout = timeout; + this.readTimeout = timeout; + this.bufferLength = bufferLength; + } + + /** + * Construct the transport object + * + * @param proxy + * Specifies the proxy server to use for accessing the web + * service or null if a direct connection is + * available + * @param url + * Specifies the web service url + * + */ + public Transport(Proxy proxy, String url) { + this.proxy = proxy; + this.url = url; + } + + public Transport(Proxy proxy, String url, int timeout) { + this.proxy = proxy; + this.url = url; + this.timeout = timeout; + this.readTimeout = timeout; + } + + public Transport(Proxy proxy, String url, int timeout, int bufferLength) { + this.proxy = proxy; + this.url = url; + this.timeout = timeout; + this.readTimeout = timeout; + this.bufferLength = bufferLength; } /** * Sets up the parsing to hand over to the envelope to deserialize. */ - protected void parseResponse(SoapEnvelope envelope, InputStream is) throws XmlPullParserException, IOException { + protected void parseResponse(SoapEnvelope envelope, InputStream is) + throws XmlPullParserException, IOException { XmlPullParser xp = new KXmlParser(); 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) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); + protected byte[] createRequestData(SoapEnvelope envelope, String encoding) + throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(bufferLength); + byte result[] = null; bos.write(xmlVersionTag.getBytes()); XmlSerializer xw = new KXmlSerializer(); - xw.setOutput(bos, null); + + final Iterator keysIter = prefixes.keySet().iterator(); + + xw.setOutput(bos, encoding); + while (keysIter.hasNext()) { + String key = (String) keysIter.next(); + xw.setPrefix(key, (String) prefixes.get(key)); + } envelope.write(xw); xw.flush(); bos.write('\r'); bos.write('\n'); bos.flush(); - return bos.toByteArray(); + result = bos.toByteArray(); + xw = null; + bos = null; + return result; + } + + /** + * Serializes the request. + */ + protected byte[] createRequestData(SoapEnvelope envelope) + throws IOException { + return createRequestData(envelope, null); } /** @@ -89,6 +187,12 @@ public void setUrl(String url) { this.url = url; } + public String getUrl() + { + return url; + } + + /** * Sets the version tag for the outgoing soap call. Example @@ -106,14 +210,95 @@ public void setXmlVersionTag(String tag) { public void reset() { } + /** + * 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 List of HeaderProperty + * 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 + * List of HeaderProperty headers to + * send with the SOAP request. + * + * @return Headers returned by the web service as a List of + * HeaderProperty 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 List of HeaderProperty + * 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 + * List of HeaderProperty 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 List of + * HeaderProperty instances. + */ + 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. */ - abstract public void call(String targetNamespace, SoapEnvelope envelope) throws IOException, XmlPullParserException; + 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 + */ + 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 Port number + */ + public int getPort() throws MalformedURLException { + + return new URL(url).getPort(); + } + + /** + * Return the path to the web service target + * + * @return The URL's path + */ + public String getPath() throws MalformedURLException { + + return new URL(url).getPath(); + } + abstract public ServiceConnection getServiceConnection() throws IOException; } diff --git a/ksoap2-base/src/test/java/org/ksoap2/SoapEnvelopeTest.java b/ksoap2-base/src/test/java/org/ksoap2/SoapEnvelopeTest.java index 6f2d9a65..48f8eef2 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/SoapEnvelopeTest.java +++ b/ksoap2-base/src/test/java/org/ksoap2/SoapEnvelopeTest.java @@ -46,8 +46,8 @@ public void testInitialConfigurationCorrect_Version12() { SoapEnvelope envelope = new SoapEnvelope(SoapEnvelope.VER12); assertEquals(SoapEnvelope.XSI, envelope.xsi); assertEquals(SoapEnvelope.XSD, envelope.xsd); - assertEquals(SoapEnvelope.ENC2001, envelope.enc); - assertEquals(SoapEnvelope.ENV2001, envelope.env); + assertEquals(SoapEnvelope.ENC2003, envelope.enc); + assertEquals(SoapEnvelope.ENV2003, envelope.env); assertEquals(SoapEnvelope.VER12, envelope.version); } diff --git a/ksoap2-base/src/test/java/org/ksoap2/SoapFaultTest.java b/ksoap2-base/src/test/java/org/ksoap2/SoapFaultTest.java index 20957267..ddb15bc4 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/SoapFaultTest.java +++ b/ksoap2-base/src/test/java/org/ksoap2/SoapFaultTest.java @@ -20,33 +20,85 @@ package org.ksoap2; -import java.io.*; +import junit.framework.TestCase; +import org.ksoap2.transport.ServiceConnectionFixture; +import org.kxml2.io.KXmlParser; +import org.kxml2.io.KXmlSerializer; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; -import junit.framework.*; - -import org.ksoap2.transport.*; -import org.kxml2.io.*; -import org.xmlpull.v1.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; public class SoapFaultTest extends TestCase { private static final String FAULT_STRING = "The ISBN value contains invalid characters"; + + + public void testPlaceHolder() { + // Just here so JUnit doesn't complain. + return; + } + public void testFaultDeserialize() throws Throwable { SoapFault fault = generateFaultFromFaultString(ServiceConnectionFixture.FAULT_STRING); assertEquals(ServiceConnectionFixture.FAULT_MESSAGE_STRING, fault.faultstring); } + public void testFaultDeserialize12() throws Throwable { + SoapFault12 fault = generateFaultFromFaultString12(ServiceConnectionFixture.FAULT_STRING_12); + assertEquals(ServiceConnectionFixture.FAULT_MESSAGE_STRING_12, fault.getMessage()); + } + + public void testFaultDeserialize12LegacyInterface() throws Throwable { + SoapFault12 fault = generateFaultFromFaultString12(ServiceConnectionFixture.FAULT_STRING_12); + assertEquals(ServiceConnectionFixture.FAULT_MESSAGE_STRING_12, fault.faultstring); + } + public void testFaultSerialize() throws Throwable { KXmlSerializer xmlWriter = new KXmlSerializer(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); xmlWriter.setOutput(outputStream, "UTF-8"); SoapFault fault = generateFaultFromFaultString(ServiceConnectionFixture.FAULT_STRING); fault.write(xmlWriter); - // TODO: looks like there might be a problem with the output. There are duplicate open open tags. - String possibleOutputString = "soap:Client"+FAULT_STRING+" 19318224-D The first nine characters must be digits. The last character may be a digit or the letter 'X'. Case is not important. "; + + String possibleOutputString = "" + + "soap:Client"+FAULT_STRING+"" + + " " + + " 19318224-D" + + " " + + " The first nine characters must be digits. The last" + + " character may be a digit or the letter 'X'. Case is" + + " not important. " + + " "; String faultString = new String(outputStream.toByteArray()); assertEquals(possibleOutputString, faultString); } + + /** + * + * If someone wants to fix this test case, feel free! + * + public void testFaultSerialize12() throws Throwable { + KXmlSerializer xmlWriter = new KXmlSerializer(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + xmlWriter.setOutput(outputStream, "UTF-8"); + SoapFault12 fault = generateFaultFromFaultString12(ServiceConnectionFixture.FAULT_STRING_12); + fault.write(xmlWriter); + + String possibleOutputString = " + q0:Client.AuthenticationFailed\n" + + "Authentication failed\n" + + ""; + + + String faultString = new String(outputStream.toByteArray()); + assertEquals(possibleOutputString, faultString); + + } + */ private SoapFault generateFaultFromFaultString(String faultString) throws XmlPullParserException, IOException { SoapFault fault = new SoapFault(); @@ -60,5 +112,17 @@ private SoapFault generateFaultFromFaultString(String faultString) throws XmlPul return fault; } + private SoapFault12 generateFaultFromFaultString12(String faultString) throws XmlPullParserException, IOException { + SoapFault12 fault = new SoapFault12(SoapEnvelope.VER12); + XmlPullParser parser = new KXmlParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(new StringReader(faultString)); + parser.nextTag(); + parser.nextTag(); + parser.nextTag(); + fault.parse(parser); + return fault; + } + } diff --git a/ksoap2-base/src/test/java/org/ksoap2/serialization/MarshalHashtableTest.java b/ksoap2-base/src/test/java/org/ksoap2/serialization/MarshalHashtableTest.java index fd3beff1..41d8be9f 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/serialization/MarshalHashtableTest.java +++ b/ksoap2-base/src/test/java/org/ksoap2/serialization/MarshalHashtableTest.java @@ -25,7 +25,8 @@ public void testWriteInstance() throws IOException { // the mock just appends the bits together assertEquals(KEY1_NAME + ";" + VALUE1, writer.getOutputText()); - assertEquals(MockXmlSerializer.PREFIX + ":string;" + MockXmlSerializer.PREFIX + ":string", writer.getPropertyType()); + assertEquals(MockXmlSerializer.PREFIX + ":string;" + MockXmlSerializer.PREFIX + ":string", + writer.getPropertyType()); assertEquals("item;key;value", writer.getStartTag()); assertEquals("key;value;item", writer.getEndtag()); @@ -35,7 +36,8 @@ public void testWriteInstance() throws IOException { marshalHashtable.writeInstance(writer, hashTable); assertEquals("key2;12;"+KEY1_NAME + ";" + VALUE1, writer.getOutputText()); - assertEquals(MockXmlSerializer.PREFIX + ":string;" + MockXmlSerializer.PREFIX + ":int;"+MockXmlSerializer.PREFIX + ":string;" + MockXmlSerializer.PREFIX + ":string", writer.getPropertyType()); + assertEquals(MockXmlSerializer.PREFIX + ":string;" + MockXmlSerializer.PREFIX + ":int;" + + MockXmlSerializer.PREFIX + ":string;" + MockXmlSerializer.PREFIX + ":string", writer.getPropertyType()); assertEquals("item;key;value;item;key;value", writer.getStartTag()); assertEquals("key;value;item;key;value;item", writer.getEndtag()); } diff --git a/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapObjectTest.java b/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapObjectTest.java index f68ba99a..0288703b 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapObjectTest.java +++ b/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapObjectTest.java @@ -7,31 +7,83 @@ public class SoapObjectTest extends TestCase { private static final String ANOTHER_PROPERTY_NAME = "anotherProperty"; private static final String A_PROPERTY_NAME = "aPropertyName"; private SoapObject soapObject; + private SoapObject mojSoapObejObject; protected void setUp() throws Exception { super.setUp(); soapObject = new SoapObject("namespace", "name"); + mojSoapObejObject = new SoapObject("nameSpace", "RemoteProject"); } public void testFormattingOfToString() { final String localValue = "propertyValue"; soapObject.addProperty(A_PROPERTY_NAME, "propertyValue"); - assertEquals("name{" + A_PROPERTY_NAME + "=propertyValue; }", soapObject.toString()); + assertEquals("name{" + A_PROPERTY_NAME + "=propertyValue; }", + soapObject.toString()); soapObject.addProperty(ANOTHER_PROPERTY_NAME, new Integer(12)); - assertEquals("name{" + A_PROPERTY_NAME + "=" + localValue + "; " + ANOTHER_PROPERTY_NAME + "=12; }", soapObject.toString()); + assertEquals("name{" + A_PROPERTY_NAME + "=" + localValue + "; " + + ANOTHER_PROPERTY_NAME + "=12; }", soapObject.toString()); } public void testEquals() { + + // Different name results in false + SoapObject differentSoapObject = new SoapObject("namespace", "fred"); + assertFalse(soapObject.equals(differentSoapObject)); + assertFalse(differentSoapObject.equals(soapObject)); + + // different namespace results in false + differentSoapObject = new SoapObject("fred", "name"); + assertFalse(differentSoapObject.equals(soapObject)); + + // same results in true SoapObject soapObject2 = new SoapObject("namespace", "name"); assertTrue(soapObject.equals(soapObject2)); + assertTrue(soapObject2.equals(soapObject)); + // missing property results in false. soapObject.addProperty(A_PROPERTY_NAME, new Integer(12)); assertFalse(soapObject.equals(soapObject2)); + assertFalse(soapObject2.equals(soapObject)); - soapObject2.addProperty(A_PROPERTY_NAME, soapObject.getProperty(A_PROPERTY_NAME)); + // identical properties results in true + soapObject2.addProperty(A_PROPERTY_NAME, + soapObject.getProperty(A_PROPERTY_NAME)); assertTrue(soapObject.equals(soapObject2)); + assertTrue(soapObject2.equals(soapObject)); + + // different properties result in a false + soapObject.addProperty("anotherProperty", new Integer(12)); + soapObject2.addProperty("anotherPropertyFoo", + soapObject.getProperty(A_PROPERTY_NAME)); + assertFalse(soapObject.equals(soapObject2)); + assertFalse(soapObject2.equals(soapObject)); + + // same properties with different order should be false + soapObject.addProperty("anotherPropertyFoo", new Integer(12)); + soapObject2.addProperty("anotherProperty", + soapObject.getProperty(A_PROPERTY_NAME)); + assertFalse(soapObject.equals(soapObject2)); + assertFalse(soapObject2.equals(soapObject)); + + soapObject2 = soapObject.newInstance(); + + SoapObject multipleAddresses = new SoapObject("namespace", "name"); + multipleAddresses.addProperty("address", "941 Wealthy"); + multipleAddresses.addProperty("address", "942 Wealthy"); + + assertTrue(multipleAddresses.equals(multipleAddresses)); + + // Different number of attributes should result in equals returning + // false + soapObject2.addAttribute("Attribute1", new Integer(14)); + assertFalse(soapObject.equals(soapObject2)); - soapObject.equals("bob"); + // Different values of attributes should return false; + soapObject2.addAttribute("Attribute1", new Integer(19)); + assertFalse(soapObject.equals(soapObject2)); + + assertFalse(soapObject.equals("bob")); assertTrue(soapObject.newInstance().equals(soapObject)); @@ -51,14 +103,350 @@ public void testSameProperties_DifferentValues() { assertFalse(soapObject2.equals(soapObject)); } - public void testGetPropertyWithIllegalPropertyName() { + public void testGetAttribute_AttributesExist() { + soapObject.addAttribute("First", "one"); + soapObject.addAttribute("Second", "two"); + + assertEquals("two", soapObject.getAttribute("Second")); + assertEquals("one", soapObject.getAttribute("First")); + } + + public void testGetAttribute_AttributeDoesNotExist() { + soapObject.addAttribute("First", "one"); + + try { + soapObject.getAttribute("Second"); + fail("should have thrown"); + } catch (RuntimeException e) { + assertEquals(RuntimeException.class.getName(), e.getClass() + .getName()); + assertEquals("illegal property: Second", e.getMessage()); + } + } + + public void testHasAttribute_KnowsIfTheAttributeExists() { + soapObject.addAttribute("Second", "two"); + assertTrue(soapObject.hasAttribute("Second")); + assertFalse(soapObject.hasAttribute("First")); + } + + public void testGetAttributeSafely_GivesAttributeWhenItExists() { + soapObject.addAttribute("First", "one"); + soapObject.addAttribute("Second", "two"); + + assertEquals("two", soapObject.getAttributeSafely("Second")); + assertEquals("one", soapObject.getAttributeSafely("First")); + } + + public void testGetAttributeSafely_GivesNullWhenTheAttributeDoesNotExist() { + soapObject.addAttribute("Second", "two"); + + assertEquals("two", soapObject.getAttributeSafely("Second")); + assertNull(soapObject.getAttributeSafely("First")); + } + + public void testGetProperty_GivesPropertyWhenItExists() { + soapObject.addProperty("Prop1", "One"); + soapObject.addProperty("Prop8", "Eight"); + + assertEquals("One", soapObject.getProperty("Prop1")); + assertEquals("Eight", soapObject.getProperty("Prop8")); + } + + public void testHasProperty_KnowsWhenThePropertyExists() { + soapObject.addProperty("Prop8", "Eight"); + assertTrue(soapObject.hasProperty("Prop8")); + assertFalse(soapObject.hasProperty("Prop1")); + } + + public void testHasProperty_namespace() { + soapObject.addProperty("test_namespace","Prop8", "Eight"); + assertTrue(soapObject.hasProperty("test_namespace","Prop8")); + assertTrue(soapObject.hasProperty("Prop8")); + assertFalse(soapObject.hasProperty("wrong_namespace","Prop8")); + } + + public void testGetProperty_ThrowsWhenIllegalPropertyName() { try { soapObject.getProperty("blah"); fail(); } catch (RuntimeException e) { - assertEquals(RuntimeException.class.getName(), e.getClass().getName()); + assertEquals(RuntimeException.class.getName(), e.getClass() + .getName()); + assertEquals("illegal property: blah", e.getMessage()); + } + } + + public void testGetProperty_namespace_ThrowsWhenIllegalPropertyName() { + try { + Object obj=soapObject.getProperty("namespace", "blah"); + fail(); + } catch (RuntimeException e) { + assertEquals(RuntimeException.class.getName(), e.getClass() + .getName()); + assertEquals("illegal property: blah", e.getMessage()); + } + } + + public void testGetPropertySafely_GivesPropertyWhenItExists() { + soapObject.addProperty("Prop1", "One"); + soapObject.addProperty("Prop8", "Eight"); + + assertEquals("One", soapObject.getPropertySafely("Prop1")); + assertEquals("Eight", soapObject.getPropertySafely("Prop8")); + } + + public void testGetPropertySafely_namespace_GivesPropertyWhenItExists() { + soapObject.addProperty("namespace","Prop1", "One"); + soapObject.addProperty("namespace","Prop8", "Eight"); + + assertEquals("One", soapObject.getPropertyByNamespaceSafely("namespace","Prop1")); + assertEquals("Eight", soapObject.getPropertyByNamespaceSafely("namespace", "Prop8")); + assertEquals("One", soapObject.getPropertySafely("Prop1")); + assertEquals("Eight", soapObject.getPropertySafely("Prop8")); + } + + public void testGetPropertySafely_GivesANullObjectWhenThePropertyDoesNotExist() { + Object nullObject = soapObject.getPropertySafely("Prop1"); + assertNotNull(nullObject); + assertNull(nullObject.toString()); + } + + public void testGetPropertySafely_namespace_GivesANullObjectWhenThePropertyDoesNotExist() { + Object nullObject = soapObject.getPropertyByNamespaceSafely("namespace", "Prop1"); + assertNotNull(nullObject); + assertNull(nullObject.toString()); + } + + public void testGetPropertySafely_CanReturnTheGivenObjectWhenThePropertyDoesNotExist() { + String thinger = "thinger"; + Integer five = new Integer(5); + assertSame(thinger, soapObject.getPropertySafely("Prop8", thinger)); + assertSame(five, soapObject.getPropertySafely("Prop8", five)); + } + + public void testAddPropertyIfValue() { + String name = "NotHere"; + String value = null; + soapObject.addPropertyIfValue(name, value); + assertFalse(soapObject.hasProperty(name)); + + PropertyInfo propertyInfo = new PropertyInfo(); + propertyInfo.name = name; + propertyInfo.value = value; + + soapObject.addPropertyIfValue(propertyInfo); + + assertFalse(soapObject.hasProperty(name)); + + soapObject.addPropertyIfValue(propertyInfo, null); + assertFalse(soapObject.hasProperty(name)); + + soapObject.addPropertyIfValue(propertyInfo, "GotOne"); + assertTrue(soapObject.hasProperty(name)); + } + + public void testAddPropertyIfValue_namespace() { + String name = "NotHere"; + String value = null; + soapObject.addPropertyIfValue("namespace",name, value); + assertFalse(soapObject.hasProperty(name)); + assertFalse(soapObject.hasProperty("namespace",name)); + + PropertyInfo propertyInfo = new PropertyInfo(); + propertyInfo.name = name; + propertyInfo.value = value; + propertyInfo.namespace = "namespace"; + + soapObject.addPropertyIfValue(propertyInfo); + + assertFalse(soapObject.hasProperty(name)); + assertFalse(soapObject.hasProperty("namespace",name)); + + } + + public void testAddAttributeIfValue() { + String name = "NotHere"; + String value = null; + soapObject.addAttributeIfValue(name, value); + assertFalse(soapObject.hasAttribute(name)); + + AttributeInfo attributeInfo = new AttributeInfo(); + attributeInfo.name = name; + attributeInfo.value = value; + + soapObject.addAttributeIfValue(attributeInfo); + + assertFalse(soapObject.hasAttribute(name)); + + soapObject.addAttribute(name, "GotOne"); + assertTrue(soapObject.hasAttribute(name)); + } + + public void testGetPropertyAsString() { + String name = "StringProperty"; + String value = "a string"; + soapObject.addProperty(name, value); + + assertEquals(value, soapObject.getPropertyAsString(name)); + + String name2 = "NotThere"; + assertEquals("", soapObject.getPropertySafelyAsString(name2)); + assertEquals(value, soapObject.getPropertySafelyAsString(name)); + + String anInteger = "AnInteger"; + String integerValue = "12"; + + soapObject.addProperty(anInteger, new Integer(12)); + assertEquals(integerValue, soapObject.getPropertyAsString(anInteger)); + + mojSoapObejObject.addProperty("jaaa", null); + assertEquals("", + mojSoapObejObject.getPropertySafelyAsString("jaaa")); + + assertTrue("".equals(soapObject.getPropertySafelyAsString(null))); + + // tests for later comments on http://code.google.com/p/ksoap2-android/issues/detail?id=94 + assertTrue("".equals(soapObject.getPropertySafelyAsString(null, null))); + + assertTrue("test".equals(soapObject.getPropertySafelyAsString(null, "test"))); + } + + public void getPropertyByNamespaceSafelyAsString() { + String name = "StringProperty"; + String value = "a string"; + String namespace = "namespace"; + soapObject.addProperty(namespace,name, value); + + assertEquals(value, soapObject.getPropertyByNamespaceSafelyAsString(namespace,name)); + + String name2 = "NotThere"; + assertEquals("", soapObject.getPropertyByNamespaceSafelyAsString(namespace,name2)); + assertEquals(value, soapObject.getPropertyByNamespaceSafelyAsString(namespace,name)); + + String anInteger = "AnInteger"; + String integerValue = "12"; + + soapObject.addProperty(anInteger, new Integer(12)); + assertEquals(integerValue, soapObject.getPropertyByNamespaceSafelyAsString(namespace,anInteger)); + + mojSoapObejObject.addProperty(namespace,"jaaa", null); + assertEquals("", + mojSoapObejObject.getPropertyByNamespaceSafelyAsString(namespace,"jaaa")); + + } + + public void testGetAttributeAsString() { + String name = "StringAttribute"; + String value = "a string"; + soapObject.addAttribute(name, value); + + assertEquals(value, soapObject.getAttributeAsString(name)); + + String name2 = "NotThere"; + assertEquals("", soapObject.getAttributeSafelyAsString(name2)); + assertEquals(value, soapObject.getAttributeSafelyAsString(name)); + + String anInteger = "AnInteger"; + String integerValue = "12"; + + soapObject.addAttribute(anInteger, new Integer(12)); + assertEquals(integerValue, + soapObject.getAttributeSafelyAsString(anInteger)); + } + + public void testGetPrimitiveProperty(){ + PropertyInfo propertyInfo = new PropertyInfo(); + + propertyInfo.name = "ComplexThing"; + propertyInfo.type = SoapObject.class; + propertyInfo.value = soapObject; + + soapObject.addProperty(propertyInfo); + + propertyInfo = new PropertyInfo(); + propertyInfo.name = "PrimitiveThing"; + propertyInfo.type = String.class; + propertyInfo.value = "thing"; + soapObject.addProperty(propertyInfo); + + assertSame("",soapObject.getPrimitiveProperty("ComplexThing").toString()); + assertSame("thing",soapObject.getPrimitiveProperty("PrimitiveThing").toString()); + try { + soapObject.getPrimitiveProperty("blah"); + fail(); + } catch (RuntimeException e) { + assertEquals(RuntimeException.class.getName(), e.getClass() + .getName()); assertEquals("illegal property: blah", e.getMessage()); } } + + public void testGetPrimitivePropertyAsString(){ + PropertyInfo propertyInfo = new PropertyInfo(); + + propertyInfo.name = "ComplexThing"; + propertyInfo.type = SoapObject.class; + propertyInfo.value = soapObject; + + soapObject.addProperty(propertyInfo); + + propertyInfo = new PropertyInfo(); + propertyInfo.name = "PrimitiveThing"; + propertyInfo.type = String.class; + propertyInfo.value = "thing"; + soapObject.addProperty(propertyInfo); + + assertSame("",soapObject.getPrimitivePropertyAsString("ComplexThing")); + assertSame("thing",soapObject.getPrimitivePropertyAsString("PrimitiveThing")); + try { + soapObject.getPrimitivePropertyAsString("blah"); + fail(); + } catch (RuntimeException e) { + assertEquals(RuntimeException.class.getName(), e.getClass() + .getName()); + assertEquals("illegal property: blah", e.getMessage()); + } + } + + public void testGetPrimitivePropertySafely(){ + PropertyInfo propertyInfo = new PropertyInfo(); + + propertyInfo.name = "ComplexThing"; + propertyInfo.type = SoapObject.class; + propertyInfo.value = soapObject; + + soapObject.addProperty(propertyInfo); + + propertyInfo = new PropertyInfo(); + propertyInfo.name = "PrimitiveThing"; + propertyInfo.type = String.class; + propertyInfo.value = "thing"; + soapObject.addProperty(propertyInfo); + + assertSame("",soapObject.getPrimitivePropertySafely("ComplexThing").toString()); + assertSame("thing",soapObject.getPrimitivePropertySafely("PrimitiveThing").toString()); + assertEquals(null,soapObject.getPropertySafely("jaaa").toString()); + } + + public void testGetPrimitivePropertySafelyAsString(){ + PropertyInfo propertyInfo = new PropertyInfo(); + + propertyInfo.name = "ComplexThing"; + propertyInfo.type = SoapObject.class; + propertyInfo.value = soapObject; + + soapObject.addProperty(propertyInfo); + + propertyInfo = new PropertyInfo(); + propertyInfo.name = "PrimitiveThing"; + propertyInfo.type = String.class; + propertyInfo.value = "thing"; + soapObject.addProperty(propertyInfo); + + assertSame("",soapObject.getPrimitivePropertySafelyAsString("ComplexThing").toString()); + assertSame("thing",soapObject.getPrimitivePropertySafelyAsString("PrimitiveThing").toString()); + assertEquals("",soapObject.getPropertySafelyAsString("jaaa").toString()); + } } diff --git a/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapPrimitiveTest.java b/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapPrimitiveTest.java index 20c73410..b20e01ea 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapPrimitiveTest.java +++ b/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapPrimitiveTest.java @@ -4,7 +4,15 @@ public class SoapPrimitiveTest extends TestCase { - public void testEquals() { + private SoapPrimitive soapPrimitive; + + protected void setUp() throws Exception { + super.setUp(); + soapPrimitive = new SoapPrimitive("namespace", "name", "theValue"); + } + + + public void testEqualsWithoutAttributes() { SoapPrimitive primitive = new SoapPrimitive("namespace", "name", "value"); assertFalse(primitive.equals("something that shouldn't equal")); @@ -39,4 +47,44 @@ public void testEquals_NullNamespace() { assertFalse(primitive.equals(new SoapPrimitive("weeee", "name", "value"))); } + public void testGetAttribute_AttributesExist() { + soapPrimitive.addAttribute("First", "one"); + soapPrimitive.addAttribute("Second", "two"); + + assertEquals("two", soapPrimitive.getAttribute("Second")); + assertEquals("one", soapPrimitive.getAttribute("First")); + } + + public void testGetAttribute_AttributeDoesNotExist() { + soapPrimitive.addAttribute("First", "one"); + + try { + soapPrimitive.getAttribute("Second"); + fail("should have thrown"); + } catch (RuntimeException e) { + assertEquals(RuntimeException.class.getName(), e.getClass().getName()); + assertEquals("illegal property: Second", e.getMessage()); + } + } + + public void testHasAttribute_KnowsIfTheAttributeExists() { + soapPrimitive.addAttribute("Second", "two"); + assertTrue(soapPrimitive.hasAttribute("Second")); + assertFalse(soapPrimitive.hasAttribute("First")); + } + + public void testGetAttributeSafely_GivesAttributeWhenItExists() { + soapPrimitive.addAttribute("First", "one"); + soapPrimitive.addAttribute("Second", "two"); + + assertEquals("two", soapPrimitive.getAttributeSafely("Second")); + assertEquals("one", soapPrimitive.getAttributeSafely("First")); + } + + public void testSafeGetAttribute_GivesNullWhenTheAttributeDoesNotExist() { + soapPrimitive.addAttribute("Second", "two"); + + assertEquals("two", soapPrimitive.getAttributeSafely("Second")); + assertNull(soapPrimitive.getAttributeSafely("First")); + } } diff --git a/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapSerializationEnvelopeTest.java b/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapSerializationEnvelopeTest.java index 933f463b..a3184dc7 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapSerializationEnvelopeTest.java +++ b/ksoap2-base/src/test/java/org/ksoap2/serialization/SoapSerializationEnvelopeTest.java @@ -36,476 +36,668 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -public class SoapSerializationEnvelopeTest extends TestCase -{ - private static final String PARAMETER_NAME = "aParameter"; - private static String FUNCTION_NAME = "FunctionName"; - private static String NAMESPACE_NAME = ServiceConnectionFixture.NAMESPACE; - private static final String BODY_XML_STRING = ""; - private KXmlSerializer xmlWriter; - private SoapSerializationEnvelope envelope; - private ByteArrayOutputStream outputStream; - private SoapObject soapObject; - private MockTransport myTransport; - - protected void setUp() throws Exception - { - super.setUp(); - xmlWriter = new KXmlSerializer(); - outputStream = new ByteArrayOutputStream(); - xmlWriter.setOutput(outputStream, "UTF-8"); - envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); - envelope.addMapping(NAMESPACE_NAME, ServiceConnectionFixture.RESPONSE_CLASS_NAME, - ServiceConnectionFixture.RESPONSE_CLASS); - soapObject = new SoapObject(NAMESPACE_NAME, FUNCTION_NAME); - myTransport = new MockTransport(); - } - - // public void xx_testTwoDimensionalStringArrays() throws Throwable { - // // can't handle two dimensional arrays. - // myTransport.parseResponse(envelope, - // ServiceConnectionFixture.createTwoDimensionalStringArrayResponseAsStream()); - // Object result = envelope.getResponse(); - // ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); - // } - - public void testInbound() throws Throwable - { - myTransport.parseResponse(envelope, ServiceConnectionFixture.createWorkingNoMultirefAsStream()); - Object result = envelope.getResponse(); - ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); - - myTransport.parseResponse(envelope, ServiceConnectionFixture.createWorkingAsStream()); - result = envelope.getResponse(); - ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); - - myTransport.parseResponse(envelope, ServiceConnectionFixture - .createWorkingNoMultirefAsStream_reversedResponseParameters()); - result = envelope.getResponse(); - ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); - - // Can't handle multirefs yet - // - // myTransport.parseResponse(envelope, - // ServiceConnectionFixture.createMultirefAsStream()); - // result = envelope.getResult(); - // ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) - // result); - - } - - public void testReadInstance_SoapObject_Reversed() throws Throwable - { - KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture - .createWorkingNoMultirefAsStream_reversedResponseParameters()); - SoapSerializationEnvelope localEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); - SoapObject aSoapObject = (SoapObject) localEnvelope.readUnknown(parser, NAMESPACE_NAME, - ServiceConnectionFixture.RESPONSE_CLASS_NAME); - assertEquals(ServiceConnectionFixture.theStringResponse, aSoapObject.getProperty(0)); - assertEquals("" + ServiceConnectionFixture.theLongResponse, aSoapObject.getProperty(1).toString()); - } - - public void testReadInstance_SoapObject() throws Throwable - { - KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture - .createWorkingNoMultirefAsStream()); - SoapSerializationEnvelope localEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); - SoapObject aSoapObject = (SoapObject) localEnvelope.readUnknown(parser, NAMESPACE_NAME, - ServiceConnectionFixture.RESPONSE_CLASS_NAME); - assertEquals(ServiceConnectionFixture.theStringResponse, aSoapObject.getProperty(1)); - assertEquals("" + ServiceConnectionFixture.theLongResponse, aSoapObject.getProperty(0).toString()); - } - - public void testReadSerializable_ParameterOrderReverse() throws Throwable - { - ComplexResponse complexResponse = new ComplexResponse(); - KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture - .createWorkingNoMultirefAsStream_reversedResponseParameters()); - envelope.readSerializable(parser, complexResponse); - ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); - } - - public void testReadSerializable_ParameterOrderNormal() throws Throwable - { - ComplexResponse complexResponse = new ComplexResponse(); - KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture - .createWorkingNoMultirefAsStream()); - envelope.readSerializable(parser, complexResponse); - ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); - } - - public void testReadSerializable_ParameterOrderNormal_NullNamespace() throws Throwable - { - ComplexResponse complexResponse = new ComplexResponse(); - complexResponse.namespace = null; - KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture - .createWorkingNoMultirefAsStream()); - envelope.readSerializable(parser, complexResponse); - ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); - } - - public void testReadSerializable_ParameterOrderNormal_NullNamespace_NullName() - { - // SF Bug # 1442028 - try - { - ComplexResponse complexResponse = new ComplexResponse(); - complexResponse.namespace = null; - complexResponse.parameterCount = 2; - complexResponse.responseOne_Name = null; - KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture - .createWorkingNoMultirefAsStream()); - envelope.readSerializable(parser, complexResponse); - ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); - } - catch (Throwable e) - { - assertFalse(e instanceof NullPointerException); - } - } - - private KXmlParser primedParserForSerializableParameterTest(InputStream inputStream) throws Throwable - { - KXmlParser parser = new KXmlParser(); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(inputStream, null); - parser.nextTag(); - parser.nextTag(); - parser.nextTag(); - parser.nextTag(); - return parser; - } - - public void testWriteHashtable() throws IOException - { - Hashtable hashtable = new Hashtable(); - hashtable.put("key1", "value1"); - soapObject.addProperty("hashthingy", hashtable); - new MarshalHashtable().register(envelope); - writeBodyWithSoapObject(soapObject); - assertEquals( - BODY_XML_STRING - + ">" - + "key1value1", - new String(outputStream.toByteArray())); - } - - public void testReadHashtable() throws XmlPullParserException, IOException - { - new MarshalHashtable().register(envelope); - myTransport.parseResponse(envelope, ServiceConnectionFixture.hashTableAsStream()); - Hashtable result = (Hashtable) envelope.bodyIn; - assertEquals("value1", result.get("key1")); - } - - public void testReadHashtable_dupkeyvalueandnulls() throws XmlPullParserException, IOException - { - new MarshalHashtable().register(envelope); - myTransport.parseResponse(envelope, ServiceConnectionFixture.hashTableWithDupAsStream()); - Hashtable result = (Hashtable) envelope.bodyIn; - assertEquals("value1", result.get("key1")); - assertEquals(1, result.values().size()); - } - - public void testWritingBody_WithNullParameter() throws Exception - { - soapObject.addProperty(PARAMETER_NAME, null); - writeBodyWithSoapObject(soapObject); - assertEquals(BODY_XML_STRING + ">" + "<" + PARAMETER_NAME + " n2:null=\"true\" xmlns:n2=\"" - + envelope.xsi + "\" />" + END_XML_FUNCTION_STRING, new String(outputStream.toByteArray())); - } - - public void testWritingBody_WithPrimitiveBooleanParameters() throws Exception - { - assertPrimitiveParameterCorrect(Boolean.TRUE, "boolean"); - } - - public void testWritingBody_WithPrimitiveStringParameters() throws Exception - { - assertPrimitiveParameterCorrect("aStringValue", "string"); - } - - public void testWritingBody_WithPrimitiveIntegerParameters() throws Exception - { - assertPrimitiveParameterCorrect(new Integer(2), "int"); - } - - public void testWritingBody_WithPrimitiveLongParameters() throws Exception - { - assertPrimitiveParameterCorrect(new Long(2), "long"); - } - - private void assertPrimitiveParameterCorrect(Object primtiveValue, String type) throws IOException - { - soapObject.addProperty(PARAMETER_NAME, primtiveValue); - writeBodyWithSoapObject(soapObject); - assertEquals(BODY_XML_STRING + ">" + getParameterBody(type, primtiveValue) + END_XML_FUNCTION_STRING, - new String(outputStream.toByteArray())); - } - - public void testWritingBody_NullBody() throws IOException - { - envelope.setOutputSoapObject(null); - try - { - envelope.writeBody(xmlWriter); - fail(); - } - catch (NullPointerException e) - { - // TODO: This should probably do something intelligent instead of - // throwing a null pointer exception - } - } - - public void testWritingBody_EmptyBody() throws Exception - { - writeBodyWithSoapObject(soapObject); - assertEquals(BODY_XML_STRING + END_XML_STRING, new String(outputStream.toByteArray())); - } - - private String getParameterBody(String type, Object aValue) - { - return "<" + PARAMETER_NAME + " n3:type=\"n2:" + type + "\" xmlns:n2=\"" + envelope.xsd - + "\" xmlns:n3=\"" + envelope.xsi + "\">" + aValue + ""; - } - - private void writeBodyWithSoapObject(SoapObject soapObject) throws IOException - { - envelope.setOutputSoapObject(soapObject); - envelope.writeBody(xmlWriter); - xmlWriter.flush(); - } - - /** Proof that the service was called, and how often. */ - static protected int serviceCallCount; - - /* - * We're going to execute "GetStatus" according to the following WSDL snippet. This is done in pieces as - * unit tests. The definition is from the OPCFoundation OPC XML DA WSDL - * (http://opcfoundation.org/webservices/XMLDA/1.0/). The document from http://www.opcfoundation.com also - * provides examples of the transactions. - * - * - * - * - * - * - * - * - * - * - * - * In other words, we call "getStatus" on the service, with "LocaleID" and "ClientRequestHandle" available - * as attributes. The response has two objects "ReplyBase" and "ServerStatus". Each of these have a - * hodgepog of attributes, sequences and enumerations. - * - * The output message should look, more or less like this (from the specification): - * - * - * - * - * and the response more or less like this (from the specification): - * - * - * OPC XML Data - * Access 1.00 Sample Server en - * en-US de - * XML_DA_Version_1_0 - * - */ - - /** - * This will generate an XML string from a SoapObject/SoapEnvelope that represents the "getStatus" call in - * the WSDL above. The resulting XML will be passed to "public void testGetStatus(String xmlString)" to - * ensure AXIS compatibility (and compatibility with the published standards). - */ - public void testGetStatusSoapObject() throws Throwable - { - SoapObject getStatus = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", "getStatus"); - getStatus.addAttribute("LocaleID", "de-AT"); - getStatus.addAttribute("ClientRequestHandle", "ClientHandle"); - SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); - envelope.bodyOut = getStatus; - envelope.setAddAdornments(false); - - byte[] request = myTransport.createRequestData(envelope); - String xmlString = new String(request); - assertGetStatus(xmlString); - } - - /** The string that represents the "getStatus". This is copied from an Axis call. */ - protected static final String getStatusRequest = "" - + "" - + ""; - - /** - * Test the status using the AXIS generated xml. - * - * @throws Throwable - */ - public void testGetStatus() throws Throwable - { - assertGetStatus(getStatusRequest); - } - - /** - * Test getStatus by passing in an xmlString. The result should be the same with an Axis or ksoap - * generated string (clearly). - * - * @param xmlString - * the xml string to test. - * @throws Throwable - */ - public void assertGetStatus(String xmlString) throws Throwable - { - serviceCallCount = 0; // zero this - Object service = new GetStatus(); - envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "getStatus", SoapObject.class); - envelope.setAddAdornments(false); - ByteArrayInputStream bis = new ByteArrayInputStream(xmlString.getBytes()); - XmlPullParser parser = new KXmlParser(); - parser.setInput(bis, "UTF-8"); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - envelope.parse(parser); - SoapObject soapReq = (SoapObject) envelope.bodyIn; - assertEquals("ClientHandle", soapReq.getAttribute("ClientRequestHandle")); - SoapObject result = null; - result = MockTransport.invoke(service, soapReq); - - assertEquals("Service Called ", 1, serviceCallCount); - // assert contents of result; - } - - /** - * This will generate an XML string from a SoapObject/SoapEnvelope that represents the "GetStatusResponse" - * call in the WSDL above. The resulting XML will be passed to - * "public void testGetStatusResponse(String xmlString)" to ensure AXIS compatibility (and compatibility - * with the published standards). - */ - public void testGetStatusResponseSoapObject() throws Throwable - { - SoapObject getStatusResponse = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", - "GetStatusResponse"); - SoapObject getStatusResult = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", - "GetStatusResult"); - getStatusResult.addAttribute("RcvTime", "2003-05-26T20:17:42.4781250-07:00"); - getStatusResult.addAttribute("ReplyTime", "2003-05-26T20:17:42.5781250-07:00"); - getStatusResult.addAttribute("RevisedLocaleID", "de"); - getStatusResult.addAttribute("ServerState", "running"); - SoapObject status = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", "Status"); - status.addAttribute("StartTime", "2003-05-26T20:16:45.0937500-07:00"); - status.addAttribute("ProductVersion", "1.00.1.00"); - status.addProperty("VendorInfo", "OPC XML Data Access 1.00 Sample Server"); - status.addProperty("SupportedLocaleIDs", "en"); - status.addProperty("SupportedLocaleIDs", "en-US"); - status.addProperty("SupportedLocaleIDs", "de"); - status.addProperty("SupportedInterfaceVersions", "XML_DA_Version_1_0"); - getStatusResponse.addProperty("GetStatusResult", getStatusResult); - getStatusResponse.addProperty("Status", status); - SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); - envelope.bodyOut = getStatusResponse; - envelope.implicitTypes = true; - envelope.setAddAdornments(false); - byte[] request = null; - request = myTransport.createRequestData(envelope); - String xmlString = new String(request); - assertGetStatusResponse(xmlString); - } - - /** - * GetStatusResponse XML. The body is from the OPC Foundation manual, the envelope is from the AXIS - * envelope above. - */ - protected static final String getStatusResponse = "" - + "" - + " " - + " " - + " " + " " - + " OPC XML Data Access 1.00 Sample Server" - + " en" - + " en-US" - + " de" - + " XML_DA_Version_1_0" - + " " + " " + "" + ""; - - /** - * Test the response from "getStatus". The body is from the OPC Foundation manual, the envelope is from - * the AXIS envelope above. - * - * @throws Throwable - */ - public void testGetStatusResponse() throws Throwable - { - assertGetStatusResponse(getStatusResponse); - } - - /** - * Test the response from "getStatus". - * - * @throws Throwable - */ - public void assertGetStatusResponse(String xmlString) throws Throwable - { - ByteArrayInputStream is = new ByteArrayInputStream(xmlString.toString().getBytes()); - envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "GetStatusResponse", - SoapObject.class); - envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "Status", SoapObject.class); - envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "GetStatusResult", - SoapObject.class); - myTransport.parseResponse(envelope, is); - is.close(); - SoapObject response = (SoapObject) envelope.bodyIn; - assertEquals(" Two Parameter (GetStatusResponse)", 2, ((SoapObject) response).getPropertyCount()); - assertEquals(" No Attributes (GetStatusResponse)", 0, ((SoapObject) response).getAttributeCount()); - // first property is "GetStatusResult" - SoapObject getStatusResult = (SoapObject) response.getProperty("GetStatusResult"); - assertNotNull(" GetStatusResult ", getStatusResult); - assertEquals(" No Parameters (GetStatusResult)", 0, getStatusResult.getPropertyCount()); - assertEquals(" Four Attributes (GetStatusResult)", 4, getStatusResult.getAttributeCount()); - assertEquals("2003-05-26T20:17:42.4781250-07:00", getStatusResult.getAttribute("RcvTime")); - assertEquals("2003-05-26T20:17:42.5781250-07:00", getStatusResult.getAttribute("ReplyTime")); - assertEquals("running", getStatusResult.getAttribute("ServerState")); - // first property is "Status" - SoapObject status = (SoapObject) response.getProperty("Status"); - assertEquals(" Five Parameters (Status)", 5, status.getPropertyCount()); - assertEquals(" Two Attributes (Status)", 2, status.getAttributeCount()); - assertEquals("2003-05-26T20:16:45.0937500-07:00", status.getAttribute("StartTime")); - assertEquals("1.00.1.00", status.getAttribute("ProductVersion")); - } - - public static class GetStatus - { - public SoapObject getStatus(SoapObject in) - { - serviceCallCount++; - assertEquals("Should be two attributes. ", 2, in.getAttributeCount()); - assertEquals("LocaleID ", "de-AT", in.getAttribute("LocaleID")); - assertEquals("ClientRequestHandle ", "ClientHandle", in.getAttribute("ClientRequestHandle")); - return null; - } - }; - +/** + * + * @author James Seigel (original author) + * @author Manfred Moser (minor test additions) + */ +public class SoapSerializationEnvelopeTest extends TestCase { + private static final String PARAMETER_NAME = "aParameter"; + private static String FUNCTION_NAME = "FunctionName"; + private static String NAMESPACE_NAME = ServiceConnectionFixture.NAMESPACE; + private static final String BODY_XML_STRING = ""; + private KXmlSerializer xmlWriter; + private SoapSerializationEnvelope envelope; + private ByteArrayOutputStream outputStream; + private SoapObject soapObject; + private MockTransport myTransport; + + protected void setUp() throws Exception { + super.setUp(); + xmlWriter = new KXmlSerializer(); + outputStream = new ByteArrayOutputStream(); + xmlWriter.setOutput(outputStream, "UTF-8"); + envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + envelope.addMapping(NAMESPACE_NAME, ServiceConnectionFixture.RESPONSE_CLASS_NAME, + ServiceConnectionFixture.RESPONSE_CLASS); + soapObject = new SoapObject(NAMESPACE_NAME, FUNCTION_NAME); + myTransport = new MockTransport(); + } + + // public void xx_testTwoDimensionalStringArrays() throws Throwable { + // // can't handle two dimensional arrays. + // myTransport.parseResponse(envelope, + // ServiceConnectionFixture.createTwoDimensionalStringArrayResponseAsStream()); + // Object result = envelope.getResponse(); + // ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); + // } + + + // Test that we can parse a response as an "unknown" type an include attributes on primitives. + + public void testInboundWithAttributesOnPrimitives() throws Throwable { + myTransport.parseResponse(envelope, ServiceConnectionFixture.createWorkingNoMultirefWithAttributesAsStream()); + SoapObject cfr = (SoapObject) envelope.getResponse(); + assertEquals(4, cfr.getPropertyCount()); + + + SoapPrimitive longResp = (SoapPrimitive) cfr.getProperty("longResponse"); + assertEquals(ServiceConnectionFixture.theLongResponse + "", longResp.toString()); + assertEquals("valueBar", longResp.getAttributeSafely("attrFoo")); + + assertEquals(ServiceConnectionFixture.theStringResponse, cfr.getProperty("stringResponse").toString()); + assertEquals(ServiceConnectionFixture.theIntegerResponse + "", + cfr.getProperty(ComplexResponse.INTEGER_REPONSE_NAME).toString()); + assertEquals(ServiceConnectionFixture.theBooleanResponse + "", + cfr.getProperty(ComplexResponse.BOOLEAN_RESPONSE_NAME).toString()); + + + } + + public void testInbound() throws Throwable { + myTransport.parseResponse(envelope, ServiceConnectionFixture.createWorkingNoMultirefAsStream()); + Object result = envelope.getResponse(); + ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); + + myTransport.parseResponse(envelope, ServiceConnectionFixture.createWorkingAsStream()); + result = envelope.getResponse(); + ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); + + myTransport.parseResponse(envelope, ServiceConnectionFixture + .createWorkingNoMultirefAsStream_reversedResponseParameters()); + result = envelope.getResponse(); + ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) result); + + // Can't handle multirefs yet + // + // myTransport.parseResponse(envelope, + // ServiceConnectionFixture.createMultirefAsStream()); + // result = envelope.getResult(); + // ServiceConnectionFixture.assertComplexResponseCorrect((ComplexResponse) + // result); + + } + + public void testRealLifeResponse() throws Exception { + myTransport.parseResponse(envelope, ServiceConnectionFixture.createRealLifeResponse()); + SoapObject result = (SoapObject) envelope.getResponse(); + + SoapPrimitive item = (SoapPrimitive) result.getProperty(0); + assertEquals("Alpine Urgent Care", item.getAttributeSafely("GetCensusByUrgentCarePROD2ResultKey")); + assertEquals("1", item.toString()); + } + + + public void testReadInstance_SoapObject_Reversed() throws Throwable { + KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture + .createWorkingNoMultirefAsStream_reversedResponseParameters()); + SoapSerializationEnvelope localEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + SoapObject aSoapObject = (SoapObject) localEnvelope.readUnknown(parser, NAMESPACE_NAME, + ServiceConnectionFixture.RESPONSE_CLASS_NAME); + assertEquals(ServiceConnectionFixture.theStringResponse, aSoapObject.getProperty(0)); + assertEquals("" + ServiceConnectionFixture.theLongResponse, aSoapObject.getProperty(1).toString()); + } + + public void testReadInstance_SoapObject() throws Throwable { + KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture + .createWorkingNoMultirefAsStream()); + SoapSerializationEnvelope localEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + SoapObject aSoapObject = (SoapObject) localEnvelope.readUnknown(parser, NAMESPACE_NAME, + ServiceConnectionFixture.RESPONSE_CLASS_NAME); + assertEquals(ServiceConnectionFixture.theStringResponse, aSoapObject.getProperty(1)); + assertEquals("" + ServiceConnectionFixture.theLongResponse, aSoapObject.getProperty(0).toString()); + } + + public void testReadSerializable_ParameterOrderReverse() throws Throwable { + ComplexResponse complexResponse = new ComplexResponse(); + KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture + .createWorkingNoMultirefAsStream_reversedResponseParameters()); + envelope.readSerializable(parser, complexResponse); + ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); + } + + public void testReadSerializable_ParameterOrderNormal() throws Throwable { + ComplexResponse complexResponse = new ComplexResponse(); + KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture + .createWorkingNoMultirefAsStream()); + envelope.readSerializable(parser, complexResponse); + ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); + } + + public void testReadSerializable_ParameterOrderNormal_NullNamespace() throws Throwable { + ComplexResponse complexResponse = new ComplexResponse(); + complexResponse.namespace = null; + KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture + .createWorkingNoMultirefAsStream()); + envelope.readSerializable(parser, complexResponse); + ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); + } + + public void testReadSerializable_ParameterOrderNormal_NullNamespace_NullName() { + // SF Bug # 1442028 + try { + ComplexResponse complexResponse = new ComplexResponse(); + complexResponse.namespace = null; + complexResponse.parameterCount = 2; + complexResponse.responseOne_Name = null; + KXmlParser parser = primedParserForSerializableParameterTest(ServiceConnectionFixture + .createWorkingNoMultirefAsStream()); + envelope.readSerializable(parser, complexResponse); + ServiceConnectionFixture.assertComplexResponseCorrect(complexResponse); + } + catch (Throwable e) { + assertFalse(e instanceof NullPointerException); + } + } + + private KXmlParser primedParserForSerializableParameterTest(InputStream inputStream) throws Throwable { + KXmlParser parser = new KXmlParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(inputStream, null); + parser.nextTag(); + parser.nextTag(); + parser.nextTag(); + parser.nextTag(); + return parser; + } + + public void testWriteHashtable() throws IOException { + Hashtable hashtable = new Hashtable(); + hashtable.put("key1", "value1"); + soapObject.addProperty("hashthingy", hashtable); + new MarshalHashtable().register(envelope); + writeBodyWithSoapObject(soapObject); + assertEquals( + BODY_XML_STRING + + ">" + + "key1value1" + + "", + + new String(outputStream.toByteArray())); + } + + public void testReadHashtable() throws XmlPullParserException, IOException { + new MarshalHashtable().register(envelope); + myTransport.parseResponse(envelope, ServiceConnectionFixture.hashTableAsStream()); + Hashtable result = (Hashtable) envelope.bodyIn; + assertEquals("value1", result.get("key1")); + } + + public void testReadHashtable_dupkeyvalueandnulls() throws XmlPullParserException, IOException { + new MarshalHashtable().register(envelope); + myTransport.parseResponse(envelope, ServiceConnectionFixture.hashTableWithDupAsStream()); + Hashtable result = (Hashtable) envelope.bodyIn; + assertEquals("value1", result.get("key1")); + assertEquals(1, result.values().size()); + } + + public void testWritingBody_WithNullParameter() throws Exception { + soapObject.addProperty(PARAMETER_NAME, null); + writeBodyWithSoapObject(soapObject); + assertEquals(BODY_XML_STRING + ">" + "<" + PARAMETER_NAME + " n2:null=\"true\" xmlns:n2=\"" + + envelope.xsi + "\" />" + END_XML_FUNCTION_STRING, new String(outputStream.toByteArray())); + } + + public void testWritingBody_WithPrimitiveBooleanParameters() throws Exception { + assertPrimitiveParameterCorrect(Boolean.TRUE, "boolean"); + } + + public void testWritingBody_WithPrimitiveStringParameters() throws Exception { + assertPrimitiveParameterCorrect("aStringValue", "string"); + } + + public void testWritingBody_WithPrimitiveIntegerParameters() throws Exception { + assertPrimitiveParameterCorrect(new Integer(2), "int"); + } + + public void testWritingBody_WithPrimitiveLongParameters() throws Exception { + assertPrimitiveParameterCorrect(new Long(2), "long"); + } + + private void assertPrimitiveParameterCorrect(Object primtiveValue, String type) throws IOException { + soapObject.addProperty(PARAMETER_NAME, primtiveValue); + writeBodyWithSoapObject(soapObject); + assertEquals(BODY_XML_STRING + ">" + getParameterBody(type, primtiveValue) + END_XML_FUNCTION_STRING, + new String(outputStream.toByteArray())); + } + + public void testWritingBody_NullBody() throws IOException { + envelope.setOutputSoapObject(null); + envelope.writeBody(xmlWriter); + // null body no longer fails + } + + public void testWritingBody_SetEmpty() throws IOException { + envelope.setBodyOutEmpty(true); + envelope.writeBody(xmlWriter); + } + + public void testWritingBody_EmptyBody() throws Exception { + writeBodyWithSoapObject(soapObject); + assertEquals(BODY_XML_STRING + END_XML_STRING, new String(outputStream.toByteArray())); + } + + public void testWritingBody_NestedSoapObject() throws Exception { + soapObject.addSoapObject(createNestedSoapObject()); + writeBodyWithSoapObject(soapObject); + } + + public void testWritingBody_PropertyOfTypeSoapObject() throws Exception { + soapObject.addProperty("objectproperty", createNestedSoapObject()); + writeBodyWithSoapObject(soapObject); + } + + private SoapObject createNestedSoapObject() { + SoapObject nested = new SoapObject(null, "nested"); + nested.addProperty("nestedprop", "nestedpropvalue"); + return nested; + } + + private String getParameterBody(String type, Object aValue) { + return "<" + PARAMETER_NAME + " n3:type=\"n2:" + type + "\" xmlns:n2=\"" + envelope.xsd + + "\" xmlns:n3=\"" + envelope.xsi + "\">" + aValue + ""; + } + + private void writeBodyWithSoapObject(SoapObject soapObject) throws IOException { + envelope.setOutputSoapObject(soapObject); + envelope.writeBody(xmlWriter); + xmlWriter.flush(); + } + + /** + * Proof that the service was called, and how often. + */ + static protected int serviceCallCount; + + /* + * We're going to execute "GetStatus" according to the following WSDL snippet. This is done in pieces as + * unit tests. The definition is from the OPCFoundation OPC XML DA WSDL + * (http://opcfoundation.org/webservices/XMLDA/1.0/). The document from http://www.opcfoundation.com also + * provides examples of the transactions. + * + * + * + * + * + * + * + * + * + * + * + * In other words, we call "getStatus" on the service, with "LocaleID" and "ClientRequestHandle" available + * as attributes. The response has two objects "ReplyBase" and "ServerStatus". Each of these have a + * hodgepog of attributes, sequences and enumerations. + * + * The output message should look, more or less like this (from the specification): + * + * + * + * + * and the response more or less like this (from the specification): + * + * + * OPC XML Data + * Access 1.00 Sample Server en + * en-US de + * XML_DA_Version_1_0 + * + */ + + /** + * This will generate an XML string from a SoapObject/SoapEnvelope that represents the "getStatus" call in + * the WSDL above. The resulting XML will be passed to "public void testGetStatus(String xmlString)" to + * ensure AXIS compatibility (and compatibility with the published standards). + */ + public void testGetStatusSoapObject() throws Throwable { + SoapObject getStatus = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", "getStatus"); + getStatus.addAttribute("LocaleID", "de-AT"); + getStatus.addAttribute("ClientRequestHandle", "ClientHandle"); + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + envelope.bodyOut = getStatus; + envelope.setAddAdornments(false); + + byte[] request = myTransport.createRequestData(envelope); + String xmlString = new String(request); + assertGetStatus(xmlString); + } + + /** + * The string that represents the "getStatus". This is copied from an Axis call. + */ + protected static final String getStatusRequest = "" + + "" + + "" + + ""; + + /** + * Test the status using the AXIS generated xml. + * + * @throws Throwable + */ + public void testGetStatus() throws Throwable { + assertGetStatus(getStatusRequest); + } + + /** + * Test getStatus by passing in an xmlString. The result should be the same with an Axis or ksoap + * generated string (clearly). + * + * @param xmlString the xml string to test. + * @throws Throwable + */ + public void assertGetStatus(String xmlString) throws Throwable { + serviceCallCount = 0; // zero this + Object service = new GetStatus(); + envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "getStatus", SoapObject.class); + envelope.setAddAdornments(false); + ByteArrayInputStream bis = new ByteArrayInputStream(xmlString.getBytes()); + XmlPullParser parser = new KXmlParser(); + parser.setInput(bis, "UTF-8"); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + envelope.parse(parser); + SoapObject soapReq = (SoapObject) envelope.bodyIn; + assertEquals("ClientHandle", soapReq.getAttribute("ClientRequestHandle")); + SoapObject result = null; + result = MockTransport.invoke(service, soapReq); + + assertEquals("Service Called ", 1, serviceCallCount); + // assert contents of result; + } + + /** + * This will generate an XML string from a SoapObject/SoapEnvelope that represents the "GetStatusResponse" + * call in the WSDL above. The resulting XML will be passed to + * "public void testGetStatusResponse(String xmlString)" to ensure AXIS compatibility (and compatibility + * with the published standards). + */ + public void testGetStatusResponseSoapObject() throws Throwable { + SoapObject getStatusResponse = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", + "GetStatusResponse"); + SoapObject getStatusResult = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", + "GetStatusResult"); + getStatusResult.addAttribute("RcvTime", "2003-05-26T20:17:42.4781250-07:00"); + getStatusResult.addAttribute("ReplyTime", "2003-05-26T20:17:42.5781250-07:00"); + getStatusResult.addAttribute("RevisedLocaleID", "de"); + getStatusResult.addAttribute("ServerState", "running"); + SoapObject status = new SoapObject("http://opcfoundation.org/webservices/XMLDA/1.0/", "Status"); + status.addAttribute("StartTime", "2003-05-26T20:16:45.0937500-07:00"); + status.addAttribute("ProductVersion", "1.00.1.00"); + status.addProperty("VendorInfo", "OPC XML Data Access 1.00 Sample Server"); + status.addProperty("SupportedLocaleIDs", "en"); + status.addProperty("SupportedLocaleIDs", "en-US"); + status.addProperty("SupportedLocaleIDs", "de"); + status.addProperty("SupportedInterfaceVersions", "XML_DA_Version_1_0"); + getStatusResponse.addProperty("GetStatusResult", getStatusResult); + getStatusResponse.addProperty("Status", status); + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + envelope.bodyOut = getStatusResponse; + envelope.implicitTypes = true; + envelope.setAddAdornments(false); + byte[] request = null; + request = myTransport.createRequestData(envelope); + String xmlString = new String(request); + assertGetStatusResponse(xmlString); + } + + /** + * GetStatusResponse XML. The body is from the OPC Foundation manual, the envelope is from the AXIS + * envelope above. + */ + protected static final String getStatusResponse = "" + + "" + + " " + + " " + + " " + " " + + " OPC XML Data Access 1.00 Sample Server" + + " en" + + " en-US" + + " de" + + " XML_DA_Version_1_0" + + " " + " " + "" + ""; + + /** + * Test the response from "getStatus". The body is from the OPC Foundation manual, the envelope is from + * the AXIS envelope above. + * + * @throws Throwable + */ + public void testGetStatusResponse() throws Throwable { + assertGetStatusResponse(getStatusResponse); + } + + /** + * Test the response from "getStatus". + * + * @throws Throwable + */ + public void assertGetStatusResponse(String xmlString) throws Throwable { + ByteArrayInputStream is = new ByteArrayInputStream(xmlString.toString().getBytes()); + envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "GetStatusResponse", + SoapObject.class); + envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "Status", SoapObject.class); + envelope.addMapping("http://opcfoundation.org/webservices/XMLDA/1.0/", "GetStatusResult", + SoapObject.class); + myTransport.parseResponse(envelope, is); + is.close(); + SoapObject response = (SoapObject) envelope.bodyIn; + assertEquals(" Two Parameter (GetStatusResponse)", 2, ((SoapObject) response).getPropertyCount()); + assertEquals(" No Attributes (GetStatusResponse)", 0, ((SoapObject) response).getAttributeCount()); + // first property is "GetStatusResult" + SoapObject getStatusResult = (SoapObject) response.getProperty("GetStatusResult"); + assertNotNull(" GetStatusResult ", getStatusResult); + assertEquals(" No Parameters (GetStatusResult)", 0, getStatusResult.getPropertyCount()); +// if(nestedSoap) { +// assertEquals(" Five Attributes (GetStatusResult)", 5, getStatusResult.getAttributeCount()); +// } else { + assertEquals(" Four Attributes (GetStatusResult)", 4, getStatusResult.getAttributeCount()); +// } + assertEquals("2003-05-26T20:17:42.4781250-07:00", getStatusResult.getAttribute("RcvTime")); + assertEquals("2003-05-26T20:17:42.5781250-07:00", getStatusResult.getAttribute("ReplyTime")); + assertEquals("running", getStatusResult.getAttribute("ServerState")); + // first property is "Status" + SoapObject status = (SoapObject) response.getProperty("Status"); + assertEquals(" Five Parameters (Status)", 5, status.getPropertyCount()); +// if(nestedSoap) { +// assertEquals(" Three Attributes (Status)", 3, status.getAttributeCount()); +// } else { + assertEquals(" Two Attributes (Status)", 2, status.getAttributeCount()); +// } + assertEquals("2003-05-26T20:16:45.0937500-07:00", status.getAttribute("StartTime")); + assertEquals("1.00.1.00", status.getAttribute("ProductVersion")); + } + + public static class GetStatus { + public SoapObject getStatus(SoapObject in) { + serviceCallCount++; + assertEquals("Should be two attributes. ", 2, in.getAttributeCount()); + assertEquals("LocaleID ", "de-AT", in.getAttribute("LocaleID")); + assertEquals("ClientRequestHandle ", "ClientHandle", in.getAttribute("ClientRequestHandle")); + return null; + } + } + + public void testAttributesOnPrimitives() throws Exception { + String testXML = "Barney" + + ""; + InputStream inputStream = new ByteArrayInputStream(testXML.getBytes()); + SoapSerializationEnvelope sse = new SoapSerializationEnvelope(SoapEnvelope.VER11); + + + KXmlParser parser = new KXmlParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(inputStream, null); + parser.nextTag(); + + sse.parseBody(parser); + + SoapPrimitive result = (SoapPrimitive) sse.getResponse(); + assertEquals("fred", result.getAttributeSafely("name")); + assertEquals("anotherValue", result.getAttributeSafely("anotherAttr")); + assertEquals("Barney", result.toString()); + } + + public void testAttributesOnPrimitives2() throws Exception { + String testXML = "" + + "Fred" + + "Chris" + + "Allison" + + ""; + InputStream inputStream = new ByteArrayInputStream(testXML.getBytes()); + SoapSerializationEnvelope sse = new SoapSerializationEnvelope(SoapEnvelope.VER11); + + + KXmlParser parser = new KXmlParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(inputStream, null); + parser.nextTag(); + + sse.parseBody(parser); + + SoapObject result = (SoapObject) sse.getResponse(); + SoapPrimitive fred = (SoapPrimitive) result.getProperty(0); + + assertEquals("F", fred.getAttributeSafely("grade")); + assertEquals("Fred", fred.toString()); + + SoapPrimitive chris = (SoapPrimitive) result.getProperty(1); + assertEquals("C", chris.getAttributeSafely("grade")); + assertEquals("Chris", chris.toString()); + + SoapPrimitive allison = (SoapPrimitive) result.getProperty(2); + assertEquals("A", allison.getAttributeSafely("grade")); + assertEquals("Allison", allison.toString()); + } + + + /** + * This test ensures that name set on the SoapObject creation as well as when adding it as a property to another + * SoapObject are kept around and used. This used to be the default behaviour up to including 2.6.0 and a regression + * broke this with 2.6.1. The 2.6.2 release fixes this again. + * + * @throws Exception + */ + public void testEnsureNameAndTypeNotLost() throws Exception { + String namespace = "namespace"; + String typeDetails = "ArrayOfDetails"; + String nameDetails = "Details"; + + String typeDetail = "DetailBase"; + String nameDetail = "Detail"; + + String expectedResponse + = "" + + "" + + "" + + "abc0" + + "0" + + "" + + "" + + "abc1" + + "1" + + "" + + "" + + "abc2" + + "2" + + "" + + "" + + ""; + + SoapObject requestSoap = new SoapObject(namespace, "PlaceOrder"); + + SoapObject details = new SoapObject(namespace, typeDetails); + int detailTotal = 3; + for (int detailCount = 0; detailCount < detailTotal; detailCount++) { + SoapObject detailSoap = new SoapObject(namespace, typeDetail); + detailSoap.addProperty("PartNumber", "abc" + detailCount); + detailSoap.addProperty("Quantity", Integer.toString(detailCount)); + + details.addProperty(nameDetail, detailSoap); + } + requestSoap.addProperty(nameDetails, details); + + envelope.addAdornments = false; + writeBodyWithSoapObject(requestSoap); + String request = new String(outputStream.toByteArray()); + assertEquals(expectedResponse, request); + } + + /** + * Test created for issue 112 that uncovered a problem with writing a SoapPrimitive with Attributes. They used to + * get lost. Not anymore about fixes to DM#writeInstance . + * @throws Exception + * @see DM#writeInstance(org.xmlpull.v1.XmlSerializer, Object) + * @see "http://code.google.com/p/ksoap2-android/issues/detail?id=112" + */ + public void testIssue112() throws Exception { + String expectedResponse + = "" + + "1500" + + ""; + + String namespace = "MyNameSpace"; + + SoapObject requestSoap = new SoapObject(namespace, "CostOfRepairs"); + SoapPrimitive power = new SoapPrimitive(namespace, "Power", Integer.toString(1500)); + power.addAttribute("Unit", "kW"); + requestSoap.addProperty("Power", power); + + envelope.implicitTypes = true; + envelope.addAdornments = false; + writeBodyWithSoapObject(requestSoap); + String request = new String(outputStream.toByteArray()); + assertEquals(expectedResponse, request); + } + + + /** + * Test created for issue 99 SoapObject newInstance() doesn't work + * @throws Exception + * @see "http://code.google.com/p/ksoap2-android/issues/detail?id=99" + */ + public void testIssue99() throws Exception { + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + + SoapObject requestSoap = new SoapObject("", "getFavouriteFilters"); + requestSoap.addProperty("token", "123123"); + + envelope.setOutputSoapObject(requestSoap); + String originalRequest = envelope.bodyOut.toString(); + + SoapObject reconnect = ((SoapObject) envelope.bodyOut).newInstance(); + reconnect.setProperty(0, "666"); + + String expectedResponse = envelope.bodyOut.toString(); + + assertTrue("Original "+originalRequest+" != Expected " + expectedResponse, + expectedResponse.equals(originalRequest) ); + } } diff --git a/ksoap2-base/src/test/java/org/ksoap2/transport/ServiceConnectionFixture.java b/ksoap2-base/src/test/java/org/ksoap2/transport/ServiceConnectionFixture.java index 6a7b4735..76e84d6b 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/transport/ServiceConnectionFixture.java +++ b/ksoap2-base/src/test/java/org/ksoap2/transport/ServiceConnectionFixture.java @@ -20,18 +20,21 @@ package org.ksoap2.transport; -import java.io.*; -import java.net.*; -import java.util.*; - -import junit.framework.*; +import junit.framework.Assert; +import org.ksoap2.transport.mock.ComplexResponse; -import org.ksoap2.transport.mock.*; +import java.io.*; +import java.net.ProtocolException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; public class ServiceConnectionFixture implements ServiceConnection { public static final String FAULT_MESSAGE_STRING = "The ISBN value contains invalid characters"; + public static final String FAULT_MESSAGE_STRING_12 ="Authentication failed"; public static final Class RESPONSE_CLASS = new ComplexResponse().getClass(); public static final String RESPONSE_CLASS_NAME = "ComplexFunctionResponse"; + private static final String UNKNOWN_CLASS_NAME = "Unknown"; public static final String NAMESPACE = "http://namespace.com/"; static public final String AXIS_FAULT_MESSAGE = "java.io.FileNotFoundException: /WebService.jws"; public static String theStringResponse = "theStringResponse"; @@ -39,187 +42,312 @@ public class ServiceConnectionFixture implements ServiceConnection { public static int theIntegerResponse = 12; public static boolean theBooleanResponse = true; public HashMap requestPropertyMap = new HashMap(); + + public static String TWO_DIMENSIONAL_STRING_ARRAY = "" + + " " + + " " + + " " + + " " + + " " + + " 1" + + " test1" + + " " + + " " + + " 2" + + " test2" + + " " + + " " + + " " + + " " + + " "; + + public static String STRING_ARRAY_STRING = "" + + " " + + " " + + " " + + " " + + " user-agent:kSOAP/2.0" + + " soapaction:""" + + " content-type:text/xml" + + " connection:close" + + " content-length:282" + + " cache-control:no-cache" + + " pragma:no-cache" + + " host:127.0.0.1:8081" + + " " + + "accept:text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + + " " + + " " + + " " + + " "; + + public static String FAULT_STRING = "" + "" + + " " + + " " + + " " + + " soap:Client" + + " " + FAULT_MESSAGE_STRING + "" + + " http://www.xyzcorp.com" + + " " + + " " + + " 19318224-D" + + " " + + " The first nine characters must be digits. The last" + + " character may be a digit or the letter 'X'. Case is" + + " not important." + + " " + + " " + + " " + + " " + + " " + + " "; - public static String TWO_DIMENSIONAL_STRING_ARRAY = ""+ - " "+ - " "+ - " "+ - " "+ - " "+ - " 1"+ - " test1"+ - " "+ - " "+ - " 2"+ - " test2"+ - " "+ - " "+ - " "+ - " "+ - " "; - - - public static String STRING_ARRAY_STRING = ""+ - " "+ - " "+ - " "+ - " "+ - " user-agent:kSOAP/2.0"+ - " soapaction:"""+ - " content-type:text/xml"+ - " connection:close"+ - " content-length:282"+ - " cache-control:no-cache"+ - " pragma:no-cache"+ - " host:127.0.0.1:8081"+ - " accept:text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2"+ - " "+ - " " + - " "+ - " "; - - public static String FAULT_STRING = "" + "" + - " " + - " " + - " " + - " soap:Client" + - " " + FAULT_MESSAGE_STRING + "" + - " http://www.xyzcorp.com" + - " " + - " " + - " 19318224-D" + - " " + - " The first nine characters must be digits. The last" + - " character may be a digit or the letter 'X'. Case is" + - " not important." + - " " + - " " + - " " + - " " + - " " + - " "; - + public static String FAULT_STRING_12 = "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "q0:Client.AuthenticationFailed\n" + + "\n" + + "\n" + + "Authentication failed\n" + + "\n" + + "\n" + + "\n" + + "\n" + + ""; + // have to see how this one works - public static String AXIS_FAULT_STRING =" "+ - " "+ - " "+ - " "+ - " soapenv:Server.userException "+ - " "+AXIS_FAULT_MESSAGE+" "+ - " "+ - " widebook.local "+ - " "+ - " "+ - " "+ - " "; - - - public static final String BROKEN_STRING = "" + "\n" + - " " + "\n" + - " " + "\n" + - " <" + RESPONSE_CLASS_NAME + " soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + - " " + "\n" + - " " + "\n" + - " " + "\n" + - " " + "\n" + - " "+theStringResponse+"" + "\n" + - " <"+ComplexResponse.INTEGER_REPONSE_NAME+" xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + - " <"+ComplexResponse.BOOLEAN_RESPONSE_NAME+" xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + - " " + "\n" + - " "+theLongResponse+"" + "\n" + - " " + "\n" + - " "; - public static final String WORKING_STRING = "" + "\n" + - " " + "\n" + - " " + "\n" + - " <" + RESPONSE_CLASS_NAME + " soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + - " " + "\n" + - " " + "\n" + - " " + "\n" + - " "+theLongResponse+"" + "\n" + - " "+theStringResponse+"" + "\n" + - " <"+ComplexResponse.INTEGER_REPONSE_NAME+" xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + - " <"+ComplexResponse.BOOLEAN_RESPONSE_NAME+" xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + - " " + "\n" + - " 10" + "\n" + - " " + "\n" + - " "; - public static final String WORKING_NOMULTIREF = "" + "\n" + - "" + "\n" + - " " + "\n" + - " <" + RESPONSE_CLASS_NAME + " soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + - " " + "\n" + - " "+theLongResponse+"" + "\n" + - " "+theStringResponse+"" + "\n" + - " <"+ComplexResponse.INTEGER_REPONSE_NAME+" xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + - " <"+ComplexResponse.BOOLEAN_RESPONSE_NAME+" xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + - " " + "\n" + - " " + "\n" + - " " + "\n" + - ""; - public static final String WORKING_NOMULTIREF_REVERSED_RESPONSE_PARAMETERS = "" + "\n" + - "" + "\n" + - " " + "\n" + - " <" + RESPONSE_CLASS_NAME + " soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + - " " + "\n" + - " "+theStringResponse+"" + "\n" + - " "+theLongResponse+"" + "\n" + - " <"+ComplexResponse.INTEGER_REPONSE_NAME+" xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + - " <"+ComplexResponse.BOOLEAN_RESPONSE_NAME+" xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + - " " + "\n" + - " " + "\n" + - " " + "\n" + - ""; - public static final String HASH_TABLE_PARAMETERS ="" + "\n" + - "" + "\n" + - " " + "\n" + - " \n"+ - " \n"+ - " key1\n"+ - " value1\n"+ - " \n"+ - " \n"+ - " " + "\n" + - ""; - - public static final String HASH_TABLE_PARAMETERS_DUP ="" + "\n" + - "" + "\n" + - " " + "\n" + - " \n"+ - " \n"+ - " key1\n"+ - " value1\n"+ - " \n"+ - " \n"+ - " key1\n"+ - " value1\n"+ - " \n"+ - " \n"+ - " \n"+ - " blah\n"+ - " \n"+ - " \n"+ - " another\n"+ - " \n"+ - " \n"+ - " \n"+ - " " + "\n" + - ""; - - - + public static String AXIS_FAULT_STRING = " " + + " " + + " " + + " " + + " soapenv:Server.userException " + + " " + AXIS_FAULT_MESSAGE + " " + + " " + + " widebook.local " + + " " + + " " + + " " + + " "; + + + public static final String BROKEN_STRING = "" + "\n" + + " " + "\n" + + " " + "\n" + + " <" + RESPONSE_CLASS_NAME + " " + + "soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + + " " + "\n" + + " " + "\n" + + " " + "\n" + + " " + "\n" + + " " + theStringResponse + "" + "\n" + + " <" + ComplexResponse.INTEGER_REPONSE_NAME + " " + + "xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + + " <" + ComplexResponse.BOOLEAN_RESPONSE_NAME + " " + + "xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + + " " + "\n" + + " " + + theLongResponse + "" + "\n" + + " " + "\n" + + " "; + public static final String WORKING_STRING = "" + "\n" + + " " + "\n" + + " " + "\n" + + " <" + RESPONSE_CLASS_NAME + " " + + "soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + + " " + "\n" + + " " + "\n" + + " " + "\n" + + " " + theLongResponse + "" + "\n" + + " " + theStringResponse + "" + "\n" + + " <" + ComplexResponse.INTEGER_REPONSE_NAME + " " + + "xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + + " <" + ComplexResponse.BOOLEAN_RESPONSE_NAME + " " + + "xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + + " " + "\n" + + " 10" + "\n" + + " " + "\n" + + " "; + + public static final String WORKING_NOMULTIREF = "" + "\n" + + "" + "\n" + + " " + "\n" + + " <" + RESPONSE_CLASS_NAME + " " + + "soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + + " " + "\n" + + " " + theLongResponse + "" + "\n" + + " " + theStringResponse + "" + "\n" + + " <" + ComplexResponse.INTEGER_REPONSE_NAME + " " + + "xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + + " <" + ComplexResponse.BOOLEAN_RESPONSE_NAME + " " + + "xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + + " " + "\n" + + " " + "\n" + + " " + "\n" + + ""; + + + // Note: The attrFoo attribute on stringResponse is nonsense: the typing of stringResponse to xsd:string means + // that the parser returns a String object. There is no object to which to attach the attributes the purpose of + // adding this attribute here is to make sure its presense doesn't break existing code. + public static final String WORKING_NOMULTIREF_WITH_ATTRIBUTES = "" + "\n" + + "" + "\n" + + " " + "\n" + + " <" + UNKNOWN_CLASS_NAME + " " + + "soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + + " " + "\n" + + " " + theLongResponse + "" + "\n" + + " " + theStringResponse + "" + "\n" + + " <" + ComplexResponse.INTEGER_REPONSE_NAME + " " + + "xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + + " <" + ComplexResponse.BOOLEAN_RESPONSE_NAME + " " + + "xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + + " " + "\n" + + " " + "\n" + + " " + "\n" + + ""; + + public static final String REAL_LIFE_QUERY = + " " + + "" + + "" + + "" + +" 1" + + "" + +" 1" + + "" + +" 2" + + "" + +" 1" + + "" + +" 0" + + "" + +" " + +" " + +""; + + + + + public static final String WORKING_NOMULTIREF_REVERSED_RESPONSE_PARAMETERS = "" + "\n" + + "" + "\n" + + " " + "\n" + + " <" + RESPONSE_CLASS_NAME + " " + + "soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n" + + " " + "\n" + + " " + theStringResponse + "" + "\n" + + " " + theLongResponse + "" + "\n" + + " <" + ComplexResponse.INTEGER_REPONSE_NAME + " " + + "xsi:type=\"xsd:int\">" + theIntegerResponse + " \n" + + " <" + ComplexResponse.BOOLEAN_RESPONSE_NAME + " " + + "xsi:type=\"xsd:boolean\">" + theBooleanResponse + " \n" + + " " + "\n" + + " " + "\n" + + " " + "\n" + + ""; + public static final String HASH_TABLE_PARAMETERS = "" + "\n" + + "" + "\n" + + " " + "\n" + + " \n" + + " \n" + + " key1\n" + + " value1\n" + + " \n" + + " \n" + + " " + "\n" + + ""; + + public static final String HASH_TABLE_PARAMETERS_DUP = "" + "\n" + + "" + "\n" + + " " + "\n" + + " \n" + + " \n" + + " key1\n" + + " value1\n" + + " \n" + + " \n" + + " key1\n" + + " value1\n" + + " \n" + + " \n" + + " \n" + + " blah\n" + + " \n" + + " \n" + + " another\n" + + " \n" + + " \n" + + " \n" + + " " + "\n" + + ""; + + private ByteArrayInputStream inputStream; public ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); public boolean connected; - + + public ServiceConnectionFixture() { + connected = true; + } + public static InputStream hashTableWithDupAsStream() { return messsageAsStream(HASH_TABLE_PARAMETERS_DUP); } - + public static InputStream hashTableAsStream() { return messsageAsStream(HASH_TABLE_PARAMETERS); } - + public static InputStream faultStringAsStream() { return messsageAsStream(FAULT_STRING); } @@ -227,15 +355,20 @@ public static InputStream faultStringAsStream() { public static InputStream createWorkingAsStream() { return messsageAsStream(WORKING_STRING); } - + public static InputStream createWorkingNoMultirefAsStream() { return messsageAsStream(WORKING_NOMULTIREF); } - + + public static InputStream createWorkingNoMultirefWithAttributesAsStream() { + return messsageAsStream(WORKING_NOMULTIREF_WITH_ATTRIBUTES); + } + + public static InputStream createWorkingNoMultirefAsStream_reversedResponseParameters() { return messsageAsStream(WORKING_NOMULTIREF_REVERSED_RESPONSE_PARAMETERS); } - + public static InputStream createMultirefAsStream() { return messsageAsStream(BROKEN_STRING); } @@ -243,18 +376,28 @@ public static InputStream createMultirefAsStream() { private static InputStream messsageAsStream(String message) { return new ByteArrayInputStream(message.getBytes()); } - - + + public void setInputSring(String inputString) { inputStream = new ByteArrayInputStream(inputString.getBytes()); } - + public void connect() throws IOException { connected = true; } public void disconnect() throws IOException { - throw new RuntimeException("ServiceConnectionFixture.disconnect is not implemented yet"); + //Set connected to false it breaks testing because the assert header/serialization/deserialization doesn't work + //But I can't leave the not implemented exception here, so there is nothing + //connected = false; + } + + public List getResponseProperties() { + return new LinkedList(); + } + + public int getResponseCode() throws IOException { + return 200; } public void setRequestProperty(String propertyName, String value) throws IOException { @@ -264,6 +407,14 @@ public void setRequestProperty(String propertyName, String value) throws IOExcep public void setRequestMethod(String post) throws ProtocolException, IOException { } + public void setFixedLengthStreamingMode(int contentLength) { + + } + + public void setChunkedStreamingMode() { + + } + public OutputStream openOutputStream() throws IOException { return outputStream; } @@ -275,7 +426,7 @@ public InputStream openInputStream() throws IOException { public InputStream getErrorStream() { throw new RuntimeException("ServiceConnectionFixture.getErrorStream is not implemented yet"); } - + public static void assertComplexResponseCorrect(ComplexResponse complexResponse) { Assert.assertEquals("theStringResponse", complexResponse.stringResponse); Assert.assertEquals(1234567890, complexResponse.longResponse); @@ -285,5 +436,19 @@ public static InputStream createTwoDimensionalStringArrayResponseAsStream() { return messsageAsStream(TWO_DIMENSIONAL_STRING_ARRAY); } + public static InputStream createRealLifeResponse() { + return messsageAsStream(REAL_LIFE_QUERY); + } + +public String getHost() { +return ""; +} + +public int getPort() { +return 80; +} +public String getPath() { +return ""; +} } diff --git a/ksoap2-base/src/test/java/org/ksoap2/transport/TransportTestCase.java b/ksoap2-base/src/test/java/org/ksoap2/transport/TransportTestCase.java index 83b7c658..0945b853 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/transport/TransportTestCase.java +++ b/ksoap2-base/src/test/java/org/ksoap2/transport/TransportTestCase.java @@ -25,16 +25,18 @@ protected void setUp() throws Exception { complexParameter.name = "Serenity"; complexParameter.count = 56; envelope.addMapping(containerNameSpaceURI, "ComplexParameter", complexParameter.getClass()); - envelope.addMapping(containerNameSpaceURI, ServiceConnectionFixture.RESPONSE_CLASS_NAME, ServiceConnectionFixture.RESPONSE_CLASS); + envelope.addMapping(containerNameSpaceURI, ServiceConnectionFixture.RESPONSE_CLASS_NAME, + ServiceConnectionFixture.RESPONSE_CLASS); soapObject.addProperty("complexFunction", complexParameter); envelope.setOutputSoapObject(soapObject); } protected void assertHeaderCorrect(ServiceConnectionFixture aServiceConnection, String aSoapAction) { assertEquals(aSoapAction, aServiceConnection.requestPropertyMap.get("SOAPAction")); - assertEquals("text/xml", aServiceConnection.requestPropertyMap.get("Content-Type")); + assertEquals("text/xml;charset=utf-8", aServiceConnection.requestPropertyMap.get("Content-Type")); assertNotNull(aServiceConnection.requestPropertyMap.get("Content-Length")); - assertEquals("kSOAP/2.0", aServiceConnection.requestPropertyMap.get("User-Agent")); + assertTrue(aServiceConnection.requestPropertyMap.get("User-Agent").toString() + .startsWith("ksoap2-android/2.6.0+")); } protected void assertSerializationDeserialization() throws SoapFault { diff --git a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexParameter.java b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexParameter.java index 49eb0a98..c41b1ba3 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexParameter.java +++ b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexParameter.java @@ -30,12 +30,13 @@ public class ComplexParameter implements KvmSerializable { public int count; public Object getProperty(int index) { - if (index == 0) + if (index == 0) { return name; - else if (index == 1) + } else if (index == 1) { return new Integer(count); - else + } else { throw new RuntimeException("invalid parameter"); + } } public int getPropertyCount() { @@ -43,13 +44,13 @@ public int getPropertyCount() { } public void setProperty(int index, Object value) { - if (index == 0 && value instanceof String) + if (index == 0 && value instanceof String) { name = (String) value; - else if (index == 1 && value instanceof Integer) + } else if (index == 1 && value instanceof Integer) { count = ((Integer) value).intValue(); - else + } else { throw new RuntimeException("invalid parameter"); - + } } public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) { @@ -66,4 +67,9 @@ public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) } } + public String getInnerText() { + return null; + } + public void setInnerText(String s) { + } } diff --git a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexResponse.java b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexResponse.java index 3d1219b6..b738c024 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexResponse.java +++ b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/ComplexResponse.java @@ -36,16 +36,17 @@ public class ComplexResponse implements KvmSerializable { public int parameterCount = 4; public Object getProperty(int index) { - if (index == 0) + if (index == 0) { return stringResponse; - else if (index == 1) + } else if (index == 1) { return new Long(longResponse); - else if (index == 2) { + } else if (index == 2) { return new Integer(integerResponse); } else if (index == 3) { return new Boolean(booleanResponse); - } else + } else { throw new RuntimeException("invalid parameter"); + } } public int getPropertyCount() { @@ -53,16 +54,18 @@ public int getPropertyCount() { } public void setProperty(int index, Object value) { - if (index == 0 && value instanceof String) + if (index == 0 && value instanceof String) { stringResponse = (String) value; - else if (index == 1 && value instanceof Long) + } else if (index == 1 && value instanceof Long) { longResponse = ((Long) value).longValue(); - else if (index == 2 ) { + } else if (index == 2 ) { integerResponse = ((Integer) value).intValue(); } else if (index == 3) { booleanResponse = ((Boolean) value).booleanValue(); - } else - throw new RuntimeException("invalid parameter in set: "+index+":"+value.toString()+":"+value.getClass().getName()); + } else { + throw new RuntimeException("invalid parameter in set: " + index + ":" + value.toString() + ":" + + value.getClass().getName()); + } } public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) { @@ -83,5 +86,9 @@ public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) } info.namespace = namespace; } - + public String getInnerText() { + return null; + } + public void setInnerText(String s) { + } } diff --git a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockTransport.java b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockTransport.java index e6f9ab80..ba7544ed 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockTransport.java +++ b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockTransport.java @@ -1,76 +1,111 @@ package org.ksoap2.transport.mock; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.PropertyInfo; import org.ksoap2.serialization.SoapObject; +import org.ksoap2.transport.ServiceConnection; import org.ksoap2.transport.Transport; import org.xmlpull.v1.XmlPullParserException; // makes the parse more visible public class MockTransport extends Transport { - public void parseResponse(SoapEnvelope envelope, InputStream is) throws XmlPullParserException, - IOException - { - super.parseResponse(envelope, is); - } + public void parseResponse(SoapEnvelope envelope, InputStream is) throws XmlPullParserException, + IOException + { + super.parseResponse(envelope, is); + } - /** - * Overriding method to make it public. - * - * @see org.ksoap2.transport.Transport#createRequestData(org.ksoap2.SoapEnvelope) - */ - public byte[] createRequestData(SoapEnvelope envelope) throws IOException - { - return super.createRequestData(envelope); - } + /** + * Overriding method to make it public. + * + * @see org.ksoap2.transport.Transport#createRequestData(org.ksoap2.SoapEnvelope) + */ + public byte[] createRequestData(SoapEnvelope envelope) throws IOException + { + return super.createRequestData(envelope); + } - public void call(String targetNamespace, SoapEnvelope envelope) throws IOException, - XmlPullParserException - { - throw new RuntimeException("call not currently implemented"); - } + public List call(String targetNamespace, SoapEnvelope envelope, List headers) throws IOException, + XmlPullParserException + { + throw new RuntimeException("call not currently implemented"); + } - /** Invoke - from SoapServlet. */ - public static SoapObject invoke(Object service, SoapObject soapReq) throws NoSuchMethodException, - InvocationTargetException, IllegalAccessException - { - String name = soapReq.getName(); - Class types[] = new Class[soapReq.getPropertyCount()]; - Object[] args = new Object[soapReq.getPropertyCount()]; - PropertyInfo arg = new PropertyInfo(); - for (int i = 0; i < types.length; i++) - { - soapReq.getPropertyInfo(i, arg); - types[i] = (Class) arg.type; - args[i] = soapReq.getProperty(i); - } - // expensive invocation here.. optimize with method cache, - // want to support method overloading so need to figure in - // the arg types.. - Object result = null; - try - { - Method method = service.getClass().getMethod(name, types); - result = method.invoke(service, args); - } - catch (NoSuchMethodException nsme) - { - // since the properties do not match the required method calls when - // attributes are present - // we will also search for a call that takes a single "SoapObject" - // as the input. - Method method = service.getClass().getMethod(name, new Class[] { SoapObject.class }); - result = method.invoke(service, new Object[] { soapReq }); - } - SoapObject response = new SoapObject(soapReq.getNamespace(), name + "Response"); - if (result != null) - response.addProperty("return", result); - return response; - } -} \ No newline at end of file + public List call(String targetNamespace, SoapEnvelope envelope, List headers, File file) + throws IOException, XmlPullParserException { + throw new RuntimeException("call not currently implemented"); + } + + public void AddHeaders(List headers) { + throw new RuntimeException("call not currently implemented"); + } + + public List RetrieveHeaders() { + throw new RuntimeException("call not currently implemented"); + } + + /** Invoke - from SoapServlet. */ + public static SoapObject invoke(Object service, SoapObject soapReq) throws NoSuchMethodException, + InvocationTargetException, IllegalAccessException + { + String name = soapReq.getName(); + Class types[] = new Class[soapReq.getPropertyCount()]; + Object[] args = new Object[soapReq.getPropertyCount()]; + PropertyInfo arg = new PropertyInfo(); + for (int i = 0; i < types.length; i++) + { + soapReq.getPropertyInfo(i, arg); + types[i] = (Class) arg.type; + args[i] = soapReq.getProperty(i); + } + // expensive invocation here.. optimize with method cache, + // want to support method overloading so need to figure in + // the arg types.. + Object result = null; + try + { + Method method = service.getClass().getMethod(name, types); + result = method.invoke(service, args); + } + catch (NoSuchMethodException nsme) + { + // since the properties do not match the required method calls when + // attributes are present + // we will also search for a call that takes a single "SoapObject" + // as the input. + Method method = service.getClass().getMethod(name, new Class[] { SoapObject.class }); + result = method.invoke(service, new Object[] { soapReq }); + } + SoapObject response = new SoapObject(soapReq.getNamespace(), name + "Response"); + if (result != null) { + response.addProperty("return", result); + } + return response; + } + + public String getHost() { + throw new RuntimeException("call not currently implemented"); + } + + public int getPort() { + throw new RuntimeException("call not currently implemented"); + } + + public String getPath() { + throw new RuntimeException("call not currently implemented"); + } + + public ServiceConnection getServiceConnection() { + throw new RuntimeException("call not currently implemented"); + } + +} diff --git a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlPullParser.java b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlPullParser.java index d1da048a..6c337582 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlPullParser.java +++ b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlPullParser.java @@ -156,4 +156,4 @@ public void setProperty(String arg0, Object arg1) throws XmlPullParserException throw new UnsupportedOperationException("MockXmlPullParser.setProperty is not implemented yet"); } -} \ No newline at end of file +} diff --git a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlSerializer.java b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlSerializer.java index 5d946016..57c3ae43 100644 --- a/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlSerializer.java +++ b/ksoap2-base/src/test/java/org/ksoap2/transport/mock/MockXmlSerializer.java @@ -12,7 +12,8 @@ public class MockXmlSerializer implements XmlSerializer { public String endtag = ""; public String startTag = ""; - public XmlSerializer attribute(String arg0, String label, String type) throws IOException, IllegalArgumentException, IllegalStateException { + public XmlSerializer attribute(String arg0, String label, String type) + throws IOException, IllegalArgumentException, IllegalStateException { propertyType += (type + ";"); return this; } @@ -33,7 +34,8 @@ public void endDocument() throws IOException, IllegalArgumentException, IllegalS throw new UnsupportedOperationException("MockXmlSerializer.endDocument is not implemented yet"); } - public XmlSerializer endTag(String arg0, String tag) throws IOException, IllegalArgumentException, IllegalStateException { + public XmlSerializer endTag(String arg0, String tag) + throws IOException, IllegalArgumentException, IllegalStateException { endtag += (tag + ";"); return this; } @@ -70,11 +72,13 @@ public Object getProperty(String arg0) { throw new UnsupportedOperationException("MockXmlSerializer.getProperty is not implemented yet"); } - public void ignorableWhitespace(String arg0) throws IOException, IllegalArgumentException, IllegalStateException { + public void ignorableWhitespace(String arg0) + throws IOException, IllegalArgumentException, IllegalStateException { throw new UnsupportedOperationException("MockXmlSerializer.ignorableWhitespace is not implemented yet"); } - public void processingInstruction(String arg0) throws IOException, IllegalArgumentException, IllegalStateException { + public void processingInstruction(String arg0) + throws IOException, IllegalArgumentException, IllegalStateException { throw new UnsupportedOperationException("MockXmlSerializer.processingInstruction is not implemented yet"); } @@ -86,11 +90,13 @@ public void setOutput(Writer arg0) throws IOException, IllegalArgumentException, throw new UnsupportedOperationException("MockXmlSerializer.setOutput is not implemented yet"); } - public void setOutput(OutputStream arg0, String arg1) throws IOException, IllegalArgumentException, IllegalStateException { + public void setOutput(OutputStream arg0, String arg1) + throws IOException, IllegalArgumentException, IllegalStateException { throw new UnsupportedOperationException("MockXmlSerializer.setOutput is not implemented yet"); } - public void setPrefix(String arg0, String arg1) throws IOException, IllegalArgumentException, IllegalStateException { + public void setPrefix(String arg0, String arg1) + throws IOException, IllegalArgumentException, IllegalStateException { throw new UnsupportedOperationException("MockXmlSerializer.setPrefix is not implemented yet"); } @@ -98,11 +104,13 @@ public void setProperty(String arg0, Object arg1) throws IllegalArgumentExceptio throw new UnsupportedOperationException("MockXmlSerializer.setProperty is not implemented yet"); } - public void startDocument(String arg0, Boolean arg1) throws IOException, IllegalArgumentException, IllegalStateException { + public void startDocument(String arg0, Boolean arg1) + throws IOException, IllegalArgumentException, IllegalStateException { throw new UnsupportedOperationException("MockXmlSerializer.startDocument is not implemented yet"); } - public XmlSerializer startTag(String arg0, String key) throws IOException, IllegalArgumentException, IllegalStateException { + public XmlSerializer startTag(String arg0, String key) + throws IOException, IllegalArgumentException, IllegalStateException { startTag += (key + ";"); return this; } @@ -112,7 +120,8 @@ public XmlSerializer text(String text) throws IOException, IllegalArgumentExcept return this; } - public XmlSerializer text(char[] arg0, int arg1, int arg2) throws IOException, IllegalArgumentException, IllegalStateException { + public XmlSerializer text(char[] arg0, int arg1, int arg2) + throws IOException, IllegalArgumentException, IllegalStateException { throw new UnsupportedOperationException("MockXmlSerializer.text is not implemented yet"); } diff --git a/ksoap2-extra-ntlm/pom.xml b/ksoap2-extra-ntlm/pom.xml new file mode 100644 index 00000000..4e9bac50 --- /dev/null +++ b/ksoap2-extra-ntlm/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + + + ksoap2-extra-ntlm + jar + + ksoap2-extra-ntlm + NTLM support + + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + + + org.apache.httpcomponents + httpclient + 4.0.1 + + + + + jcifs + jcifs + 1.3.17 + + + javax.servlet + servlet-api + + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + diff --git a/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/JCIFSEngine.java b/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/JCIFSEngine.java new file mode 100644 index 00000000..01a30ebb --- /dev/null +++ b/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/JCIFSEngine.java @@ -0,0 +1,47 @@ +package org.ksoap2.transport; + +import jcifs.ntlmssp.NtlmFlags; +import jcifs.ntlmssp.Type1Message; +import jcifs.ntlmssp.Type2Message; +import jcifs.ntlmssp.Type3Message; +import jcifs.util.Base64; +import org.apache.http.impl.auth.NTLMEngine; +import org.apache.http.impl.auth.NTLMEngineException; + +import java.io.IOException; + +/** + * Class taken from http://hc.apache.org/httpcomponents-client-ga/ntlm.html + */ +public final class JCIFSEngine implements NTLMEngine { + + private static final int TYPE_1_FLAGS = + NtlmFlags.NTLMSSP_NEGOTIATE_56 | + NtlmFlags.NTLMSSP_NEGOTIATE_128 | + NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 | + NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | + NtlmFlags.NTLMSSP_REQUEST_TARGET; + + public String generateType1Msg(final String domain, final String workstation) + throws NTLMEngineException { + final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation); + return Base64.encode(type1Message.toByteArray()); + } + + public String generateType3Msg(final String username, final String password, + final String domain, final String workstation, final String challenge) + throws NTLMEngineException { + Type2Message type2Message; + try { + type2Message = new Type2Message(Base64.decode(challenge)); + } catch (final IOException exception) { + throw new NTLMEngineException("Invalid NTLM type 2 message", exception); + } + final int type2Flags = type2Message.getFlags(); + final int type3Flags = type2Flags + & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER)); + final Type3Message type3Message = new Type3Message(type2Message, password, domain, + username, workstation, type3Flags); + return Base64.encode(type3Message.toByteArray()); + } +} diff --git a/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/NtlmAuthenticationException.java b/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/NtlmAuthenticationException.java new file mode 100644 index 00000000..983fe681 --- /dev/null +++ b/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/NtlmAuthenticationException.java @@ -0,0 +1,17 @@ +package org.ksoap2.transport; + +public class NtlmAuthenticationException extends Exception { + private static final long serialVersionUID = 1L; + + public NtlmAuthenticationException() { + super(); + } + + public NtlmAuthenticationException(String message) { + super(message); + } + + public NtlmAuthenticationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/NtlmTransport.java b/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/NtlmTransport.java new file mode 100644 index 00000000..3b875bdf --- /dev/null +++ b/ksoap2-extra-ntlm/src/main/java/org/ksoap2/transport/NtlmTransport.java @@ -0,0 +1,212 @@ +package org.ksoap2.transport; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScheme; +import org.apache.http.auth.AuthSchemeFactory; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.NTCredentials; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.auth.NTLMScheme; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.ksoap2.HeaderProperty; +import org.ksoap2.SoapEnvelope; +import org.ksoap2.serialization.SoapSerializationEnvelope; +import org.xmlpull.v1.XmlPullParserException; + +/** + * A transport to be used with NTLM. + * + * Inspired by http://hc.apache.org/httpcomponents-client-ga/ntlm.html + * + * @author Lian Hwang lian_hwang@hotmail.com + * @author Manfred Moser + */ +public class NtlmTransport extends Transport { + private String user; + private String password; + private String ntDomain; + private String ntWorkstation; + + /** + * @deprecated This constructor is deprecated. + * Use either {@link #NtlmTransport(String)} or {@link #NtlmTransport(String, int)} instead. + */ + @Deprecated + public NtlmTransport() { + } + + /** + * Creates instance of NtlmTransport with set url + * + * @param url + * the destination to POST SOAP data + */ + public NtlmTransport(String url) { + super(url); + } + + /** + * Creates instance of NtlmTransport with set url + * + * @param url + * the destination to POST SOAP data + * @param timeout + * timeout for connection and Read Timeouts (milliseconds) + */ + public NtlmTransport(String url, int timeout) { + super(url, timeout); + } + + /** + * @deprecated The first {@code url} argument is out of order here. + * Use a combination of a {@link #NtlmTransport(String)} constructor to set the service url and + * a call to {@link #setCredentials(String, String, String, String)} to set the credentials instead. + */ + @Deprecated + public void setCredentials(String url, String user, String password, String domain, String workStation) { + this.url = url; + setCredentials(user, password, domain, workStation); + } + + public void setCredentials(String user, String password, String domain, String workStation) { + this.user = user; + this.password = password; + this.ntDomain = domain; + this.ntWorkstation = workStation; + } + + public List call(String targetNamespace, SoapEnvelope envelope, List headers) + throws IOException, XmlPullParserException { + return call(targetNamespace, envelope, headers, null); + } + + public List call(String soapAction, SoapEnvelope envelope, List headers, File outputFile) + throws IOException, XmlPullParserException { + if (outputFile != null) { + // implemented in HttpTransportSE if you are willing to port.. + throw new RuntimeException("Writing to file not supported"); + } + + HttpParams httpParameters = new BasicHttpParams(); + HttpConnectionParams.setConnectionTimeout(httpParameters, this.timeout); + + DefaultHttpClient client = new DefaultHttpClient(httpParameters); + + client.getAuthSchemes().register("ntlm", new NTLMSchemeFactory()); + NTCredentials credentials = new NTCredentials(user, password, ntWorkstation, ntDomain); + client.getCredentialsProvider().setCredentials(AuthScope.ANY, credentials); + + HttpPost httpPost = new HttpPost(url); + setHeaders(soapAction, envelope, httpPost, headers); + + HttpResponse response = client.execute(httpPost); + if (response == null) { + throw new IOException("Null response"); + } + + if (response.getStatusLine().getStatusCode() == 401) { + throw new RuntimeException("Unauthorized", new NtlmAuthenticationException()); + } + + HttpEntity responseEntity = response.getEntity(); + + parseResponse(envelope, responseEntity.getContent()); + + return Arrays.asList(response.getAllHeaders()); + } + + private void setHeaders(String soapAction, SoapEnvelope envelope, HttpPost httppost, List headers) { + byte[] requestData = null; + try { + requestData = createRequestData(envelope); + } catch (IOException iOException) { + } + ByteArrayEntity byteArrayEntity = new ByteArrayEntity(requestData); + httppost.setEntity(byteArrayEntity); + httppost.addHeader("User-Agent", org.ksoap2.transport.Transport.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 + if (envelope.version != SoapSerializationEnvelope.VER12) { + httppost.addHeader("SOAPAction", soapAction); + } + + if (envelope.version == SoapSerializationEnvelope.VER12) { + httppost.addHeader("Content-Type", Transport.CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8); + } else { + httppost.addHeader("Content-Type", Transport.CONTENT_TYPE_XML_CHARSET_UTF_8); + } + + // Pass the headers provided by the user along with the call + if (headers != null) { + for (Object header : headers) { + HeaderProperty hp = (HeaderProperty) header; + httppost.addHeader(hp.getKey(), hp.getValue()); + } + } + } + + /** + * @deprecated This method is no longer necessary. Simply setup a new NtlmTransport with the + * {@link #NtlmTransport(String)} constructor and set your credentials with the + * {@link #setCredentials(String, String, String, String)} method. + */ + @Deprecated + public void setupNtlm(String dummyUrl, String userId, String password) { + } + + // NTLM Scheme factory + private class NTLMSchemeFactory implements AuthSchemeFactory { + public AuthScheme newInstance(final HttpParams params) { + // see http://www.robertkuzma.com/2011/07/ + // manipulating-sharepoint-list-items-with-android-java-and-ntlm-authentication/ + return new NTLMScheme(new JCIFSEngine()); + } + } + + public ServiceConnection getServiceConnection() throws IOException { + throw new IOException("Not using ServiceConnection in transport"); + } + + public String getHost() { + String retVal = null; + try { + retVal = new URL(url).getHost(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + 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-extra-ntlm/src/test/java/org/ksoap2/transport/NtlmTransportExample.java b/ksoap2-extra-ntlm/src/test/java/org/ksoap2/transport/NtlmTransportExample.java new file mode 100644 index 00000000..485f395c --- /dev/null +++ b/ksoap2-extra-ntlm/src/test/java/org/ksoap2/transport/NtlmTransportExample.java @@ -0,0 +1,70 @@ +package org.ksoap2.transport; + +import org.ksoap2.SoapEnvelope; +import org.ksoap2.serialization.PropertyInfo; +import org.ksoap2.serialization.SoapObject; +import org.ksoap2.serialization.SoapSerializationEnvelope; + +/** + * A transport to be used with NTLM. + * @author Lian Hwang lian_hwang@hotmail.com + */ +public class NtlmTransportExample { + + public static final String SOAP_ACTION = "http://a.com.sg/FilesToBinaryXML"; + + public static final String OPERATION_NAME = "FilesToBinaryXML"; + + public static final String WSDL_TARGET_NAMESPACE = "http://a.com.sg/"; + + public static final String SOAP_ADDRESS = "http://10.10.2.135:9091/TestNTLM/FileToBinaryXML.asmx"; + + private static final int IMAGE_NAME = 0; + private static final int IMAGE_EXTENSION = 1; + private static final int IMAGE_DIRECTORY = 2; + private static final int IMAGE_DATECREATED = 3; + private static final int IMAGE_LASTMODIFIED = 4; + private static final int IMAGE_BINARYDATA = 5; + + public static void test() { + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE, OPERATION_NAME); + + envelope.dotNet = true; + + PropertyInfo pi = new PropertyInfo(); + pi.setName("CutOffTime"); + pi.setValue("1 Jan 1900 00:00"); + request.addProperty(pi); + + pi = new PropertyInfo(); + pi.setName("Paths"); + pi.setValue("/"); + request.addProperty(pi); + + pi = new PropertyInfo(); + pi.setName("FilterExtension"); + pi.setValue("*.jpg;*.jpeg;*.gif;*.png"); + request.addProperty(pi); + + envelope.setOutputSoapObject(request); + + NtlmTransport httpTransport = new NtlmTransport(SOAP_ADDRESS); + httpTransport.setCredentials("test6", "12345678", "ntDomain", "ws"); + + try { + + httpTransport.call(SOAP_ACTION, envelope); + + SoapObject array = (SoapObject) envelope.getResponse(); + + for (int i = 0; i < array.getPropertyCount(); i++) { + SoapObject obj = (SoapObject) array.getProperty(i); + String name = obj.getPropertyAsString(IMAGE_NAME).toLowerCase(); + // String ext = obj.getPropertyAsString(IMAGE_EXTENSION).toLowerCase(); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } +} diff --git a/ksoap2-extras/.gitignore b/ksoap2-extras/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-extras/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-extras/pom.xml b/ksoap2-extras/pom.xml index d83c9677..65578b1a 100644 --- a/ksoap2-extras/pom.xml +++ b/ksoap2-extras/pom.xml @@ -1,56 +1,64 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-extras - ksoap2-extras - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - com.google.code.ksoap2-android - ksoap2-base - - - com.google.code.ksoap2-android - ksoap2-base - test-jar - test - - - com.google.code.ksoap2-android - ksoap2-midp - + ksoap2-extras + jar - - junit - junit - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - + ksoap2-extras + + + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + test-jar + test + + + com.google.code.ksoap2-android + ksoap2-midp + ${project.version} + + + + junit + junit + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + diff --git a/ksoap2-extras/src/main/java/org/ksoap2/transport/HttpTransportBasicAuth.java b/ksoap2-extras/src/main/java/org/ksoap2/transport/HttpTransportBasicAuth.java index f2bae99c..f34ea03c 100644 --- a/ksoap2-extras/src/main/java/org/ksoap2/transport/HttpTransportBasicAuth.java +++ b/ksoap2-extras/src/main/java/org/ksoap2/transport/HttpTransportBasicAuth.java @@ -51,7 +51,7 @@ public HttpTransportBasicAuth(String url, String username, String password) { this.password = password; } - protected ServiceConnection getServiceConnection() throws IOException { + public ServiceConnection getServiceConnection() throws IOException { ServiceConnectionMidp midpConnection = new ServiceConnectionMidp(url); addBasicAuthentication(midpConnection); return midpConnection; diff --git a/ksoap2-extras/src/test/java/org/ksoap2/transport/HttpTransportBasicAuthTest.java b/ksoap2-extras/src/test/java/org/ksoap2/transport/HttpTransportBasicAuthTest.java index 4de68a2c..c8649b56 100644 --- a/ksoap2-extras/src/test/java/org/ksoap2/transport/HttpTransportBasicAuthTest.java +++ b/ksoap2-extras/src/test/java/org/ksoap2/transport/HttpTransportBasicAuthTest.java @@ -60,7 +60,7 @@ public MyTransport(String url, String username, String password) { super(url, username, password); } - protected ServiceConnection getServiceConnection() throws IOException { + public ServiceConnection getServiceConnection() throws IOException { addBasicAuthentication(serviceConnection); return serviceConnection; } diff --git a/ksoap2-j2se/.gitignore b/ksoap2-j2se/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-j2se/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-j2se/pom.xml b/ksoap2-j2se/pom.xml index 0a2eee4c..2fd9340f 100644 --- a/ksoap2-j2se/pom.xml +++ b/ksoap2-j2se/pom.xml @@ -1,52 +1,62 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-j2se - ksoap2-j2se - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - com.google.code.ksoap2-android - ksoap2-base - - - com.google.code.ksoap2-android - ksoap2-base - test-jar - test - + ksoap2-j2se + jar - - junit - junit - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - + ksoap2-j2se + + + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + test-jar + test + + + com.squareup.okhttp3 + okhttp-urlconnection + + + junit + junit + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + 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 d4a161f1..61a5e2c9 100644 --- a/ksoap2-j2se/src/main/java/org/ksoap2/serialization/MarshalFloat.java +++ b/ksoap2-j2se/src/main/java/org/ksoap2/serialization/MarshalFloat.java @@ -27,7 +27,8 @@ public class MarshalFloat implements Marshal { - public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo propertyInfo) throws IOException, XmlPullParserException { + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo propertyInfo) + throws IOException, XmlPullParserException { String stringValue = parser.nextText(); Object result; if (name.equals("float")) { 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 00000000..f7fb8662 --- /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 + */ +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 e13122ca..265b62d0 100644 --- a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpTransportSE.java +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpTransportSE.java @@ -24,10 +24,15 @@ * */ package org.ksoap2.transport; -import java.io.*; +import org.ksoap2.HeaderProperty; +import org.ksoap2.SoapEnvelope; +import org.ksoap2.serialization.*; +import org.xmlpull.v1.XmlPullParserException; -import org.ksoap2.*; -import org.xmlpull.v1.*; +import java.io.*; +import java.net.Proxy; +import java.util.*; +import java.util.zip.GZIPInputStream; /** * A J2SE based HttpTransport layer. @@ -41,7 +46,54 @@ public class HttpTransportSE extends Transport { * the destination to POST SOAP data */ public HttpTransportSE(String url) { - super(url); + super(null, url); + } + + /** + * Creates instance of HttpTransportSE with set url and defines a + * proxy server to use to access it + * + * @param proxy + * Proxy information or null for direct access + * @param url + * The destination to POST SOAP data + */ + public HttpTransportSE(Proxy proxy, String url) { + super(proxy, url); + } + + /** + * Creates instance of HttpTransportSE with set url + * + * @param url + * the destination to POST SOAP data + * @param timeout + * timeout for connection and Read Timeouts (milliseconds) + */ + public HttpTransportSE(String url, int timeout) { + super(url, timeout); + } + + public HttpTransportSE(Proxy proxy, String url, int timeout) { + super(proxy, url, timeout); + } + + /** + * Creates instance of HttpTransportSE with set url + * + * @param url + * the destination to POST SOAP data + * @param timeout + * timeout for connection and Read Timeouts (milliseconds) + * @param contentLength + * Content Lenght in bytes if known in advance + */ + public HttpTransportSE(String url, int timeout, int contentLength) { + super(url, timeout); + } + + public HttpTransportSE(Proxy proxy, String url, int timeout, int contentLength) { + super(proxy, url, timeout); } /** @@ -51,56 +103,254 @@ public HttpTransportSE(String url) { * 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 { - if (soapAction == null) + 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); + } + + /** + * 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 + * List of HeaderProperty 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 + * List of HeaderProperty 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 List of + * HeaderProperty instances. + * + * @throws HttpResponseException + * an IOException when Http response code is different from 200 + */ + public List call(String soapAction, SoapEnvelope envelope, List headers, File outputFile) + throws HttpResponseException, IOException, XmlPullParserException { + + if (soapAction == null) { soapAction = "\"\""; - byte[] requestData = createRequestData(envelope); + } + + byte[] requestData = createRequestData(envelope, "UTF-8"); + requestDump = debug ? new String(requestData) : null; responseDump = null; + ServiceConnection connection = getServiceConnection(); - connection.setRequestProperty("User-Agent", "kSOAP/2.0"); - connection.setRequestProperty("SOAPAction", soapAction); - connection.setRequestProperty("Content-Type", "text/xml"); - connection.setRequestProperty("Connection", "close"); - connection.setRequestProperty("Content-Length", "" + requestData.length); + + 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 + 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); + } + + // this seems to cause issues so we are removing it + //connection.setRequestProperty("Connection", "close"); + connection.setRequestProperty("Accept-Encoding", "gzip"); + + + // 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"); - connection.connect(); - OutputStream os = connection.openOutputStream(); - os.write(requestData, 0, requestData.length); - os.flush(); - os.close(); + sendData(requestData, connection,envelope); requestData = null; - InputStream is; + 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 xmlContent = false; + int status = connection.getResponseCode(); + try { - connection.connect(); - is = connection.openInputStream(); + retHeaders = connection.getResponseProperties(); + + for (int i = 0; i < retHeaders.size(); 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")) { + gZippedContent = true; + } + } + + //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 (contentLength > 0) { + if (gZippedContent) { + is = getUnZippedInputStream( + new BufferedInputStream(connection.openInputStream(),contentLength)); + } else { + is = new BufferedInputStream(connection.openInputStream(),contentLength); + } + } } catch (IOException e) { - is = connection.getErrorStream(); - if (is == null) { - connection.disconnect(); - throw (e); + if (contentLength > 0) { + if(gZippedContent) { + is = getUnZippedInputStream( + new BufferedInputStream(connection.getErrorStream(),contentLength)); + } else { + is = new BufferedInputStream(connection.getErrorStream(),contentLength); + } + } + + 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); + } + + //we never want to drop through to attempting to parse the HTTP error stream as a SOAP response. + connection.disconnect(); + throw e; + } } } + if (debug) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[256]; - while (true) { - int rd = is.read(buf, 0, 256); - if (rd == -1) - break; - bos.write(buf, 0, rd); - } - bos.flush(); - buf = bos.toByteArray(); - responseDump = new String(buf); - is.close(); - is = new ByteArrayInputStream(buf); + is = readDebug(is, contentLength, outputFile); + } + + 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; + } + + protected void sendData(byte[] requestData, ServiceConnection connection, SoapEnvelope envelope) + throws IOException + { + connection.setRequestProperty("Content-Length", "" + requestData.length); + connection.setFixedLengthStreamingMode(requestData.length); + + OutputStream os = connection.openOutputStream(); + os.write(requestData, 0, requestData.length); + os.flush(); + os.close(); + } + + protected void parseResponse(SoapEnvelope envelope, InputStream is,List returnedHeaders) + throws XmlPullParserException, IOException + { parseResponse(envelope, is); } - protected ServiceConnection getServiceConnection() throws IOException { - return new ServiceConnectionSE(url); + + 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); + } + + byte[] buf = new byte[256]; + + while (true) { + int rd = is.read(buf, 0, 256); + if (rd == -1) { + break; + } + bos.write(buf, 0, rd); + } + + bos.flush(); + if (bos instanceof ByteArrayOutputStream) { + buf = ((ByteArrayOutputStream) bos).toByteArray(); + } + bos = null; + responseDump = new String(buf); + is.close(); + + if (outputFile != null) { + return new FileInputStream(outputFile); + } else { + return new ByteArrayInputStream(buf); + } + } + + 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); + } + } + + public ServiceConnection getServiceConnection() throws IOException { + return new ServiceConnectionSE(proxy, url, timeout, readTimeout); } -} \ No newline at end of file +} diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSE.java new file mode 100644 index 00000000..d95e6730 --- /dev/null +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSE.java @@ -0,0 +1,173 @@ +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.*; + +/** + * HttpsServiceConnectionSE is a service connection that uses a https url connection and requires explicit setting of + * host, port and file. + *

+ * The explicit setting is necessary since pure url passing and letting the Java URL class parse the string does not + * work properly on Android. + *

+ * Links for reference: + * + * @author Manfred Moser + * @see "http://stackoverflow.com/questions/2820284/ssl-on-android-strange-issue" + * @see "http://stackoverflow.com/questions/2899079/custom-ssl-handling-stopped-working-on-android-2-2-froyo" + * @see "http://code.google.com/p/android/issues/detail?id=2690" + * @see "http://code.google.com/p/android/issues/detail?id=2764" + * @see "https://gist.github.com/908048" There can be problems with the + * certificate of theof the server on older android versions. You can disable + * SSL for the versions only e.g. with an approach like this. + */ +public class HttpsServiceConnectionSE implements ServiceConnection { + + private HttpsURLConnection connection; + + /** + * Create the transport with the supplied parameters. + * + * @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(String host, int port, String file, int timeout) throws IOException { + this(null, host, port, file, timeout, timeout); + } + + /** + * Create the transport with the supplied parameters. + * + * @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 connectTimeout the timeout for the connection in milliseconds + * @param readTimeout the timeout for reading input stream in milliseconds + * @throws IOException + */ + public HttpsServiceConnectionSE(String host, int port, String file, int connectTimeout, int readTimeout) throws + IOException { + this(null, host, port, file, connectTimeout, readTimeout); + } + + /** + * 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 connectTimeout the timeout for the connection in milliseconds + * @param readTimeout the timeout for reading input stream in milliseconds + * @throws IOException + */ + public HttpsServiceConnectionSE(Proxy proxy, String host, int port, String file, int connectTimeout, int + readTimeout) 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(connectTimeout, readTimeout); + } + + private void updateConnectionParameters(int connectTimeout, int readTimeout) { + connection.setConnectTimeout(connectTimeout); + connection.setReadTimeout(readTimeout); + connection.setUseCaches(false); + connection.setDoOutput(true); + connection.setDoInput(true); + } + + public void connect() throws IOException { + connection.connect(); + } + + public void disconnect() { + connection.disconnect(); + } + + public List getResponseProperties() { + Map properties = connection.getHeaderFields(); + Set keys = properties.keySet(); + 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))); + } + } + + return retList; + } + + public int getResponseCode() throws IOException { + return connection.getResponseCode(); + } + + public void setRequestProperty(String key, String value) { + connection.setRequestProperty(key, value); + } + + public void setRequestMethod(String requestMethod) throws IOException { + connection.setRequestMethod(requestMethod); + } + + public void setFixedLengthStreamingMode(int contentLength) { + connection.setFixedLengthStreamingMode(contentLength); + } + + public void setChunkedStreamingMode() { + connection.setChunkedStreamingMode(0); + } + + + public OutputStream openOutputStream() throws IOException { + return connection.getOutputStream(); + } + + public InputStream openInputStream() throws IOException { + return connection.getInputStream(); + } + + public InputStream getErrorStream() { + return connection.getErrorStream(); + } + + public String getHost() { + return connection.getURL().getHost(); + } + + public int getPort() { + return connection.getURL().getPort(); + } + + public String getPath() { + return connection.getURL().getPath(); + } + + public void setSSLSocketFactory(SSLSocketFactory sf) { + connection.setSSLSocketFactory(sf); + } +} diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSEIgnoringConnectionClose.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSEIgnoringConnectionClose.java new file mode 100644 index 00000000..79d30cb8 --- /dev/null +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsServiceConnectionSEIgnoringConnectionClose.java @@ -0,0 +1,20 @@ +package org.ksoap2.transport; + +import java.io.IOException; + +public class HttpsServiceConnectionSEIgnoringConnectionClose extends HttpsServiceConnectionSE { + + public HttpsServiceConnectionSEIgnoringConnectionClose(String host, int port, String file, int timeout) + throws IOException { + super(host, port, file, timeout); + } + + //@Override + public void setRequestProperty(String key, String value) { + // We want to ignore any setting of "Connection: close" because + // it is buggy with Android SSL. + if (!"Connection".equalsIgnoreCase(key) || !"close".equalsIgnoreCase(value)) { + super.setRequestProperty(key, value); + } + } +} diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsTransportSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsTransportSE.java new file mode 100644 index 00000000..2ce11e15 --- /dev/null +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpsTransportSE.java @@ -0,0 +1,77 @@ +package org.ksoap2.transport; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.URL; + +/** + * HttpsTransportSE is a simple transport for https protocal based connections. It creates a #HttpsServiceConnectionSE + * with the provided parameters. + * + * @author Manfred Moser + */ +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; + + protected final String host; + protected final int port; + protected final String file; + + public HttpsTransportSE (String host, int port, String file, int timeout) { + this(host, port, file, timeout, timeout); + } + + public HttpsTransportSE (String host, int port, String file, int connectTimeout, int readTimeout) { + super(HttpsTransportSE.PROTOCOL_FULL + host + ":" + port + file, connectTimeout, readTimeout); + 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 null for direct access + */ + public HttpsTransportSE(Proxy proxy, String host, int port, String file, int timeout) { + this(proxy, host, port, file, timeout, timeout); + } + + /** + * Creates instance of HttpTransportSE with set url and defines a + * proxy server to use to access it + * + * @param proxy + * Proxy information or null for direct access + */ + public HttpsTransportSE(Proxy proxy, String host, int port, String file, int connectTimeout, int readTimeout) { + super(proxy, HttpsTransportSE.PROTOCOL_FULL + host + ":" + port + file); + this.host = host; + this.port = port; + this.file = file; + this.timeout = connectTimeout; + this.readTimeout = readTimeout; + } + + /** + * Returns the HttpsServiceConnectionSE and creates it if necessary + * @see org.ksoap2.transport.HttpsTransportSE#getServiceConnection() + */ + public ServiceConnection getServiceConnection() throws IOException + { + if(connection != null) { + return connection; + } else { + connection = new HttpsServiceConnectionSE(proxy, host, port, file, timeout, readTimeout); + return connection; + } + } +} diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpTransportSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpTransportSE.java new file mode 100644 index 00000000..6ae1fbff --- /dev/null +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpTransportSE.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Contributor(s): John D. Beatty, Dave Dash, F. Hunter, Alexander Krebs, + * Lars Mehrmann, Sean McDaniel, Thomas Strang, Renaud Tognelli + * */ +package org.ksoap2.transport; + +import java.util.List; +import java.util.ArrayList; +import java.io.*; +import java.net.Proxy; + +import org.ksoap2.*; +import org.xmlpull.v1.*; + +/** + * A J2SE based HttpTransport layer. + */ +public class KeepAliveHttpTransportSE extends HttpTransportSE { + + /** + * Creates instance of KeepAliveHttpTransportSE with set url + * + * @param url + * the destination to POST SOAP data + */ + public KeepAliveHttpTransportSE(String url) { + super(null, url); + } + + /** + * Creates instance of KeepAliveHttpTransportSE with set url and defines a + * proxy server to use to access it + * + * @param proxy + * Proxy information or null for direct access + * @param url + * The destination to POST SOAP data + */ + public KeepAliveHttpTransportSE(Proxy proxy, String url) { + super(proxy, url); + } + + /** + * Creates instance of KeepAliveHttpTransportSE with set url + * + * @param url + * the destination to POST SOAP data + * @param timeout + * timeout for connection and Read Timeouts (milliseconds) + */ + public KeepAliveHttpTransportSE(String url, int timeout) { + super(url, timeout); + } + + public KeepAliveHttpTransportSE(Proxy proxy, String url, int timeout) { + super(proxy, url, timeout); + } + + /** + * Creates instance of KeepAliveHttpTransportSE with set url + * + * @param url + * the destination to POST SOAP data + * @param timeout + * timeout for connection and Read Timeouts (milliseconds) + * @param contentLength + * Content Lenght in bytes if known in advance + */ + public KeepAliveHttpTransportSE(String url, int timeout, int contentLength) { + super(url, timeout); + } + + public KeepAliveHttpTransportSE(Proxy proxy, String url, int timeout, int contentLength) { + super(proxy, url, timeout); + } + /** + * + * set the desired soapAction header field + * + * @param soapAction + * the desired soapAction + * @param envelope + * the envelope containing the information for the soap call. + * @param headers + * a list of HeaderProperties to be http header properties when establishing the connection + * + * @return CookieJar with any cookies sent by the server + * @throws IOException + * @throws XmlPullParserException + */ + public List call(String soapAction, SoapEnvelope envelope, List headers) + throws IOException, XmlPullParserException { + + if ( headers == null ) { + headers = new ArrayList(); + } + + HeaderProperty ref = getHeader( headers, "Connection" ); + + if ( ref == null ) { + ref = new HeaderProperty("Connection","keep-alive"); + headers.add( ref ); + } else { + ref.setValue("keep-alive"); + } + + return super.call(soapAction, envelope, headers ); + + } + + protected HeaderProperty getHeader(List lista, String key) { + HeaderProperty res = null; + + if ( lista != null ) { + for( int i = 0; i < lista.size(); i++ ) { + HeaderProperty hp = (HeaderProperty)lista.get(i); + if ( key.equals( hp.getKey() ) ) { + res = hp; + break; + } + } + } + + return res; + } + +} diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpsTransportSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpsTransportSE.java new file mode 100644 index 00000000..65ba5822 --- /dev/null +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/KeepAliveHttpsTransportSE.java @@ -0,0 +1,46 @@ +/** + * Digi-Key + * http://www.digikey.com + * + * Copyright 2010 Logicopolis Technology Inc. All rights reserved. + * http://www.logicopolis.com + */ + +package org.ksoap2.transport; + +import java.io.IOException; + +/** + * KeepAliveHttpsTransport deals with the problems with the Android ssl libraries having trouble with certificates and + * certificate authorities somehow messing up connecting/needing reconnects. Added as generic class for SE since it + * might be useful in SE environments as well and can be used as an example to create your own transport + * implementations. + * + * @author Manfred Moser + * + * @see "http://groups.google.com/group/android-developers/browse_thread/thread/3dcf62e7886a213/21f912bb90a011d6" + * @see "http://code.google.com/p/android/issues/detail?id=7074" + * @see "http://crazybob.org/2010_02_01_crazyboblee_archive.html" + */ +public class KeepAliveHttpsTransportSE extends HttpsTransportSE +{ + public KeepAliveHttpsTransportSE (String host, int port, String file, int timeout) { + super(host, port, file, timeout); + } + + /** + * Get a service connection. Returns an implementation of {@link org.ksoap2.transport.ServiceConnectionSE} that + * ignores "Connection: close" request property setting and has "Connection: keep-alive" always set and is uses + * a https connection. + * @see org.ksoap2.transport.HttpTransportSE#getServiceConnection() + */ + //@Override + public ServiceConnection getServiceConnection() throws IOException + { + 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/OkHttpServiceConnectionSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/OkHttpServiceConnectionSE.java new file mode 100644 index 00000000..6f10e8f6 --- /dev/null +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/OkHttpServiceConnectionSE.java @@ -0,0 +1,150 @@ +package org.ksoap2.transport; + +import okhttp3.OkHttpClient; +import okhttp3.internal.huc.OkHttpURLConnection; +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.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * A simple ServiceConnection based on OkHttp3's URLConnection implementation + * as a workaround for Android's timeout issues + * ref. https://code.google.com/p/android/issues/detail?id=40874 + */ +public class OkHttpServiceConnectionSE implements ServiceConnection { + private HttpURLConnection connection; + private OkHttpClient client; + + /** + * Constructor taking the url to the endpoint for this soap communication + * @param url the url to open the connection to. + * @throws IOException + */ + public OkHttpServiceConnectionSE(String url) throws IOException { + this(null, url, ServiceConnection.DEFAULT_TIMEOUT); + } + + public OkHttpServiceConnectionSE(Proxy proxy, String url) throws IOException { + this(proxy, url, ServiceConnection.DEFAULT_TIMEOUT); + } + + /** + * Constructor taking the url to the endpoint for this soap communication + * @param url the url to open the connection to. + * @param timeout the connection and read timeout for the http connection in milliseconds + * @throws IOException // 20 seconds + */ + public OkHttpServiceConnectionSE(String url, int timeout) throws IOException { + this(null, url, timeout); + } + + public OkHttpServiceConnectionSE(Proxy proxy, String url, int timeout) throws IOException { + this(new OkHttpClient.Builder() + .connectTimeout(timeout, TimeUnit.MILLISECONDS) + .readTimeout(timeout, TimeUnit.MILLISECONDS) + .build(), + proxy, url, timeout); + } + + public OkHttpServiceConnectionSE(OkHttpClient client, Proxy proxy, String url, int timeout) throws IOException { + this.client = client; + connection = new OkHttpURLConnection(new URL(url), client); +// connection = (proxy == null) +// ? new HttpURLConnectionImpl(new URL(url), client) +// : (HttpURLConnectionImpl) new URL(url).openConnection(proxy); + connection.setUseCaches(false); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setConnectTimeout(timeout); + connection.setReadTimeout(timeout); // even if we connect fine we want to time out if we cant read anything.. + } + + public void connect() throws IOException { + connection.connect(); + } + + public void disconnect() { + connection.disconnect(); + } + + public List getResponseProperties() throws IOException { + List retList = new LinkedList(); + + 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); + } + + public void setRequestMethod(String requestMethod) throws IOException { + connection.setRequestMethod(requestMethod); + } + + /** + * If the length of a HTTP request body is known ahead, sets fixed length + * to enable streaming without buffering. Sets after connection will cause an exception. + * + * @param contentLength the fixed length of the HTTP request body + * @see http://developer.android.com/reference/java/net/HttpURLConnection.html + **/ + public void setFixedLengthStreamingMode(int contentLength) { + connection.setFixedLengthStreamingMode(contentLength); + } + + public void setChunkedStreamingMode() { + connection.setChunkedStreamingMode(0); + } + + public OutputStream openOutputStream() throws IOException { + return connection.getOutputStream(); + } + + public InputStream openInputStream() throws IOException { + return connection.getInputStream(); + } + + public InputStream getErrorStream() { + return connection.getErrorStream(); + } + + public String getHost() { + return connection.getURL().getHost(); + } + + public int getPort() { + return connection.getURL().getPort(); + } + + public String getPath() { + return connection.getURL().getPath(); + } +} diff --git a/ksoap2-j2se/src/main/java/org/ksoap2/transport/OkHttpTransportSE.java b/ksoap2-j2se/src/main/java/org/ksoap2/transport/OkHttpTransportSE.java new file mode 100644 index 00000000..1397f77b --- /dev/null +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/OkHttpTransportSE.java @@ -0,0 +1,59 @@ +package org.ksoap2.transport; + +import java.io.IOException; +import java.net.Proxy; +import okhttp3.OkHttpClient; + +/** + * A simple Transport based on OkHttp3's URLConnection implementation + * as a workaround for Android's timeout issues + * ref. https://code.google.com/p/android/issues/detail?id=40874 + */ +public class OkHttpTransportSE extends HttpTransportSE { + + protected final OkHttpClient client; + + public OkHttpTransportSE(Proxy proxy, String url) { + super(proxy, url); + this.client = null; + } + + public OkHttpTransportSE(Proxy proxy, String url, int timeout) { + super(proxy, url, timeout); + this.client = null; + } + + public OkHttpTransportSE(Proxy proxy, String url, int timeout, int contentLength) { + super(proxy, url, timeout, contentLength); + this.client = null; + } + + public OkHttpTransportSE(OkHttpClient client, Proxy proxy, String url, int timeout, int contentLength) { + super(proxy, url, timeout, contentLength); + this.client = client; + } + + public OkHttpTransportSE(String url) { + super(url); + this.client = null; + } + + public OkHttpTransportSE(String url, int timeout) { + super(url, timeout); + this.client = null; + } + + public OkHttpTransportSE(String url, int timeout, int contentLength) { + super(url, timeout, contentLength); + this.client = null; + } + + @Override + public ServiceConnection getServiceConnection() throws IOException { + if (client == null) { + return new OkHttpServiceConnectionSE(proxy, url, timeout); + } else { + return new OkHttpServiceConnectionSE(client, proxy, url, timeout); + } + } +} 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 b922cbd3..bcc1b28e 100644 --- a/ksoap2-j2se/src/main/java/org/ksoap2/transport/ServiceConnectionSE.java +++ b/ksoap2-j2se/src/main/java/org/ksoap2/transport/ServiceConnectionSE.java @@ -21,8 +21,15 @@ package org.ksoap2.transport; -import java.io.*; -import java.net.*; +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. @@ -34,12 +41,39 @@ public class ServiceConnectionSE implements ServiceConnection { /** * Constructor taking the url to the endpoint for this soap communication * @param url the url to open the connection to. + * @throws IOException */ public ServiceConnectionSE(String url) throws IOException { - connection = (HttpURLConnection) new URL(url).openConnection(); + this(null, url, ServiceConnection.DEFAULT_TIMEOUT); + } + + public ServiceConnectionSE(Proxy proxy, String url) throws IOException { + this(proxy, url, ServiceConnection.DEFAULT_TIMEOUT); + } + + /** + * Constructor taking the url to the endpoint for this soap communication + * @param url the url to open the connection to. + * @param timeout the connection and read timeout for the http connection in milliseconds + * @throws IOException // 20 seconds + */ + public ServiceConnectionSE(String url, int timeout) throws IOException { + this(null, url, timeout); + } + + public ServiceConnectionSE(Proxy proxy, String url, int timeout) throws IOException { + this(proxy, url, timeout, timeout); + } + + public ServiceConnectionSE(Proxy proxy, String url, int connectTimeout, int readTimeout) throws IOException { + connection = (proxy == null) + ? (HttpURLConnection) new URL(url).openConnection() + : (HttpURLConnection) new URL(url).openConnection(proxy); connection.setUseCaches(false); connection.setDoOutput(true); connection.setDoInput(true); + connection.setConnectTimeout(connectTimeout); + connection.setReadTimeout(readTimeout); } public void connect() throws IOException { @@ -50,6 +84,29 @@ public void disconnect() { connection.disconnect(); } + public List getResponseProperties() throws IOException { + List retList = new LinkedList(); + + 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); } @@ -58,6 +115,21 @@ public void setRequestMethod(String requestMethod) throws IOException { connection.setRequestMethod(requestMethod); } + /** + * If the length of a HTTP request body is known ahead, sets fixed length + * to enable streaming without buffering. Sets after connection will cause an exception. + * + * @param contentLength the fixed length of the HTTP request body + * @see http://developer.android.com/reference/java/net/HttpURLConnection.html + **/ + public void setFixedLengthStreamingMode(int contentLength) { + connection.setFixedLengthStreamingMode(contentLength); + } + + public void setChunkedStreamingMode() { + connection.setChunkedStreamingMode(0); + } + public OutputStream openOutputStream() throws IOException { return connection.getOutputStream(); } @@ -70,4 +142,15 @@ public InputStream getErrorStream() { return connection.getErrorStream(); } + public String getHost() { + return connection.getURL().getHost(); + } + + public int getPort() { + return connection.getURL().getPort(); + } + + public String getPath() { + return connection.getURL().getPath(); + } } diff --git a/ksoap2-j2se/src/test/java/org/ksoap2/transport/HttpTransportSETest.java b/ksoap2-j2se/src/test/java/org/ksoap2/transport/HttpTransportSETest.java index a06460c9..a3aa834f 100644 --- a/ksoap2-j2se/src/test/java/org/ksoap2/transport/HttpTransportSETest.java +++ b/ksoap2-j2se/src/test/java/org/ksoap2/transport/HttpTransportSETest.java @@ -44,7 +44,7 @@ public MyTransport(String url) { super(url); } - protected ServiceConnection getServiceConnection() throws IOException { + public ServiceConnection getServiceConnection() throws IOException { return serviceConnection; } } diff --git a/ksoap2-jsoup/pom.xml b/ksoap2-jsoup/pom.xml new file mode 100644 index 00000000..c58c44cb --- /dev/null +++ b/ksoap2-jsoup/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + + + ksoap2-jsoup + jar + + ksoap2-jsoup + + + + + + com.google.code.ksoap2-android + ksoap2-j2se + ${project.version} + + + org.jsoup + jsoup + 1.9.2 + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + + diff --git a/ksoap2-jsoup/src/main/java/org/ksoap2/transport/JsoupHttpTransportSE.java b/ksoap2-jsoup/src/main/java/org/ksoap2/transport/JsoupHttpTransportSE.java new file mode 100644 index 00000000..92334e44 --- /dev/null +++ b/ksoap2-jsoup/src/main/java/org/ksoap2/transport/JsoupHttpTransportSE.java @@ -0,0 +1,44 @@ +package org.ksoap2.transport; + +import org.jsoup.Jsoup; +import org.jsoup.parser.Parser; +import org.ksoap2.SoapEnvelope; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Proxy; + +public class JsoupHttpTransportSE extends HttpTransportSE { + + public JsoupHttpTransportSE(String url) { + super(url); + } + + public JsoupHttpTransportSE(String url, int timeout) { + super(url, timeout); + } + + public JsoupHttpTransportSE(String url, int timeout, int contentLength) { + super(url, timeout, contentLength); + } + + public JsoupHttpTransportSE(Proxy proxy, String url) { + super(proxy, url); + } + + public JsoupHttpTransportSE(Proxy proxy, String url, int timeout) { + super(proxy, url, timeout); + } + + public JsoupHttpTransportSE(Proxy proxy, String url, int timeout, + int contentLength) { + super(proxy, url, timeout, contentLength); + } + + @Override + protected void parseResponse(SoapEnvelope envelope, InputStream is) throws XmlPullParserException, IOException { + envelope.bodyIn = Jsoup.parse(is, "UTF-8", "", Parser.xmlParser()); + } + +} diff --git a/ksoap2-midp/.gitignore b/ksoap2-midp/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-midp/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-midp/pom.xml b/ksoap2-midp/pom.xml index 876be6a9..5c614032 100644 --- a/ksoap2-midp/pom.xml +++ b/ksoap2-midp/pom.xml @@ -1,30 +1,41 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-midp - ksoap2-midp - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - com.google.code.ksoap2-android - ksoap2-base - + ksoap2-midp + jar - - net.sourceforge.me4se - me4se - - + ksoap2-midp + + + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + + + + net.sourceforge.me4se + me4se + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + diff --git a/ksoap2-midp/src/main/java/org/ksoap2/transport/HttpTransport.java b/ksoap2-midp/src/main/java/org/ksoap2/transport/HttpTransport.java index bd88960f..e62123b2 100644 --- a/ksoap2-midp/src/main/java/org/ksoap2/transport/HttpTransport.java +++ b/ksoap2-midp/src/main/java/org/ksoap2/transport/HttpTransport.java @@ -24,13 +24,19 @@ package org.ksoap2.transport; +import java.util.List; import java.io.*; import javax.microedition.io.*; import org.ksoap2.*; +import org.ksoap2.serialization.SoapSerializationEnvelope; import org.xmlpull.v1.*; +import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.URL; + /** * Methods to facilitate SOAP calls over HTTP using the J2ME generic connection * framework. @@ -119,25 +125,60 @@ public HttpTransport(String url) { super(url); } + public HttpTransport(Proxy proxy, String url) { + super(proxy, url); + } + + public List call(String soapAction, SoapEnvelope envelope, List headers) + throws IOException, XmlPullParserException { + return call(soapAction, envelope, headers, null); + } + /** - * set the desired soapAction header field - * + * + * Call the soapaction on the remote server. + * * @param soapAction * the desired soapAction + * @param envelope + * the envelope containing the information for the soap call. + * @param headers + * a list of HeaderProperties to be http header properties when establishing the connection + * @param outputFile + * a file to stream the response into rather than parsing it, streaming happens when file is not null + * + * @return CookieJar with any cookies sent by the server + * @throws IOException + * @throws XmlPullParserException */ - public void call(String soapAction, SoapEnvelope envelope) throws IOException, XmlPullParserException { - if (soapAction == null) + public List call(String soapAction, SoapEnvelope envelope, List headers, File outputFile) + throws IOException, XmlPullParserException { + if (soapAction == null) { soapAction = "\"\""; + } byte[] requestData = createRequestData(envelope); + List retHeaders = null; + requestDump = debug ? new String(requestData) : null; responseDump = null; try { connected = true; connection = getServiceConnection(); connection.setRequestProperty("SOAPAction", soapAction); - connection.setRequestProperty("Content-Type", "text/xml"); + 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("Content-Length", "" + requestData.length); - connection.setRequestProperty("User-Agent", "kSOAP/2.0"); + connection.setRequestProperty("User-Agent", USER_AGENT); + + 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(HttpConnection.POST); os = connection.openOutputStream(); os.write(requestData, 0, requestData.length); @@ -145,28 +186,42 @@ public void call(String soapAction, SoapEnvelope envelope) throws IOException, X requestData = null; is = connection.openInputStream(); if (debug) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[256]; - while (true) { - int rd = is.read(buf, 0, 256); - if (rd == -1) - break; - bos.write(buf, 0, rd); + OutputStream bos; + if (outputFile != null) { + bos = new FileOutputStream(outputFile); + } else { + bos = new ByteArrayOutputStream(); } - bos.flush(); - buf = bos.toByteArray(); - responseDump = new String(buf); - is.close(); - is = new ByteArrayInputStream(buf); + + byte[] buf = new byte[256]; + while (true) { + int rd = is.read(buf, 0, 256); + if (rd == -1) { + break; + } + bos.write(buf, 0, rd); + } + bos.flush(); + if (bos instanceof ByteArrayOutputStream) { + buf = ((ByteArrayOutputStream) bos).toByteArray(); + } + responseDump = new String(buf); + is.close(); + is = new ByteArrayInputStream(buf); } + + retHeaders = connection.getResponseProperties(); parseResponse(envelope, is); } finally { - if (!connected) + if (!connected) { throw new InterruptedIOException(); + } reset(); } - if (envelope.bodyIn instanceof SoapFault) + if (envelope.bodyIn instanceof SoapFault) { throw ((SoapFault) envelope.bodyIn); + } + return retHeaders; } /** @@ -197,8 +252,46 @@ public void reset() { } } - protected ServiceConnection getServiceConnection() throws IOException { + public ServiceConnection getServiceConnection() throws IOException { return new ServiceConnectionMidp(url); } + public String getHost() { + + String retVal = null; + + try { + retVal = new URL(url).getHost(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + + 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-midp/src/main/java/org/ksoap2/transport/ServiceConnectionMidp.java b/ksoap2-midp/src/main/java/org/ksoap2/transport/ServiceConnectionMidp.java index c13d8087..309b2487 100644 --- a/ksoap2-midp/src/main/java/org/ksoap2/transport/ServiceConnectionMidp.java +++ b/ksoap2-midp/src/main/java/org/ksoap2/transport/ServiceConnectionMidp.java @@ -21,11 +21,18 @@ package org.ksoap2.transport; -import java.io.*; +import org.ksoap2.HeaderProperty; -import javax.microedition.io.*; +import javax.microedition.io.Connector; +import javax.microedition.io.HttpConnection; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.List; public class ServiceConnectionMidp implements ServiceConnection { + private HttpConnection connection; public ServiceConnectionMidp(String url) throws IOException { @@ -36,6 +43,28 @@ public void disconnect() throws IOException { connection.close(); } + public List getResponseProperties() { + + List retList = new LinkedList(); + int i = 0; + String key; + + try { + while (null != (key = connection.getHeaderFieldKey(i++))) { + retList.add(new HeaderProperty(key, connection.getHeaderField(i))); + } + + } catch (IOException exp) { + // Absorb errors - if this fails then cookies are the the least of our worries + } + + return retList; + } + + public int getResponseCode() throws IOException { + return connection.getResponseCode(); + } + public void setRequestProperty(String string, String soapAction) throws IOException { connection.setRequestProperty(string, soapAction); } @@ -44,6 +73,14 @@ public void setRequestMethod(String post) throws IOException { connection.setRequestMethod(post); } + public void setFixedLengthStreamingMode(int contentLength) { + // not implemented in MIDP + } + + public void setChunkedStreamingMode() { + + } + public OutputStream openOutputStream() throws IOException { return connection.openOutputStream(); } @@ -60,4 +97,15 @@ public InputStream getErrorStream() { throw new RuntimeException("ServiceConnectionMidp.getErrorStream is not available."); } + public String getHost() { + return connection.getHost(); + } + + public int getPort() { + return connection.getPort(); + } + + public String getPath() { + return connection.getFile(); + } } diff --git a/ksoap2-okhttp/pom.xml b/ksoap2-okhttp/pom.xml new file mode 100644 index 00000000..f5a58c03 --- /dev/null +++ b/ksoap2-okhttp/pom.xml @@ -0,0 +1,83 @@ + + + + ksoap2-parent + com.google.code.ksoap2-android + 3.6.5-SNAPSHOT + + 4.0.0 + + ksoap2-okhttp + + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + + + + com.squareup.okhttp3 + okhttp-urlconnection + + + jcifs + jcifs + 1.3.17 + + + javax.servlet + servlet-api + + + + + + junit + junit + test + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + test-jar + test + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + org.apache.maven.plugins + maven-javadoc-plugin + + false + + + + + \ No newline at end of file diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/serialization/MarshalFloat.java b/ksoap2-okhttp/src/main/java/org.ksoap2/serialization/MarshalFloat.java new file mode 100644 index 00000000..0bb19fa4 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/serialization/MarshalFloat.java @@ -0,0 +1,53 @@ +/* Copyright (c) 2003,2004 Stefan Haustein, Oberhausen, Rhld., Germany + * Copyright (c) 2006, James Seigel, Calgary, AB., Canada + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. */ + +package org.ksoap2.serialization; + +import java.io.*; + +import org.xmlpull.v1.*; + +public class MarshalFloat implements Marshal { + + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo propertyInfo) + throws IOException, XmlPullParserException { + final String stringValue = parser.nextText(); + if (name.equals("float")) { + return Float.valueOf(stringValue); + } else if (name.equals("double")) { + return Double.valueOf(stringValue); + } else if (name.equals("decimal")) { + return new java.math.BigDecimal(stringValue); + } else { + throw new RuntimeException("float, double, or decimal expected"); + } + } + + public void writeInstance(XmlSerializer writer, Object instance) throws IOException { + writer.text(instance.toString()); + } + + public void register(SoapSerializationEnvelope cm) { + cm.addMapping(cm.xsd, "float", Float.class, this); + cm.addMapping(cm.xsd, "double", Double.class, this); + cm.addMapping(cm.xsd, "decimal", java.math.BigDecimal.class, this); + } +} diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/transport/HttpResponseException.java b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/HttpResponseException.java new file mode 100644 index 00000000..f66d3de8 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/HttpResponseException.java @@ -0,0 +1,49 @@ +package org.ksoap2.transport; + +import okhttp3.Headers; + +import java.io.IOException; + +/** + * 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 + */ +public class HttpResponseException extends IOException { + + private int statusCode; + private Headers responseHeaders; + + HttpResponseException(int statusCode) { + this(null, statusCode); + } + + HttpResponseException(String message, int statusCode) { + this(message, statusCode, null); + } + + HttpResponseException(String message, int statusCode, Headers responseHeaders) { + super(message); + this.statusCode = statusCode; + this.responseHeaders = responseHeaders; + } + + /** + * 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 Headers getResponseHeaders() { + return responseHeaders; + } +} diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/transport/OkHttpTransport.java b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/OkHttpTransport.java new file mode 100644 index 00000000..5e8f9fa4 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/OkHttpTransport.java @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany + *

+ * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *

+ * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + *

+ * Contributor(s): John D. Beatty, Dave Dash, F. Hunter, Alexander Krebs, + * Lars Mehrmann, Sean McDaniel, Thomas Strang, Renaud Tognelli + */ +package org.ksoap2.transport; + +import okhttp3.*; +import org.ksoap2.SoapEnvelope; +import org.ksoap2.serialization.SoapSerializationEnvelope; +import org.kxml2.io.KXmlParser; +import org.kxml2.io.KXmlSerializer; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.X509TrustManager; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.Proxy; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A OkHttp based HttpTransport layer. Keep in mind that OkHttp supports Android 2.3 and above. + * For Java, the minimum requirement is 1.7. (see https://square.github.io/okhttp/ ) + *

+ * You should also add OkHttp3 dependency to your android projects. + * compile 'com.squareup.okhttp3:okhttp:3.9.1' + *

+ * If you use NTLM authentication, you should also add JCIFS Library. + * compile 'jcifs:jcifs:1.3.17' + */ +public class OkHttpTransport { + private static final String DEFAULT_CHARSET = "UTF-8"; + + public static final int DEFAULT_TIMEOUT = 20000; + protected static final String USER_AGENT_PREFIX = "ksoap2-okhttp/3.6.3"; + + static { + InputStream stream = null; + try { + stream = OkHttpTransport.class.getResourceAsStream("logging.properties"); + if (null == stream) { + stream = OkHttpTransport.class.getClassLoader() + .getResourceAsStream("logging.properties"); + } + + if (null != stream) { + LogManager.getLogManager().readConfiguration(stream); + } else { + System.err.println("Couldn't find logger configuration."); + } + } catch (IOException e) { + System.err.println("Couldn't read logger configuration."); + e.printStackTrace(); + } finally { + if (null != stream) { + try { + stream.close(); + } catch (IOException ignore) { } + } + } + } + + private final String userAgent; + private final OkHttpClient client; + private final HttpUrl url; + private final Headers headers; + private final Logger logger; + + private OkHttpTransport(OkHttpTransport.Builder builder) { + logger = Logger.getLogger(OkHttpTransport.class.getName()); + logger.setLevel(builder.debug ? Level.FINEST : Level.INFO); + + OkHttpClient.Builder clientBuilder; + if (null != builder.client) { + clientBuilder = builder.client.newBuilder(); + } else { + clientBuilder = new OkHttpClient.Builder(); + } + + clientBuilder + .connectTimeout(builder.timeout, TimeUnit.MILLISECONDS) + .readTimeout(builder.timeout, TimeUnit.MILLISECONDS); + + if (null != builder.proxy) { + clientBuilder.proxy(builder.proxy); + + if (null != builder.proxyAuthenticator) { + clientBuilder.proxyAuthenticator(builder.proxyAuthenticator); + } + } + + if (null != builder.sslSocketFactory) { + if (null == builder.trustManager) { + throw new NullPointerException("TrustManager = null"); + } + + clientBuilder.sslSocketFactory(builder.sslSocketFactory, builder.trustManager); + } + + if (null != builder.authenticator) { + clientBuilder.authenticator(builder.authenticator); + } + + client = clientBuilder.build(); + userAgent = buildUserAgent(builder); + url = builder.url; + headers = builder.headers; + } + + private String buildUserAgent(Builder builder) { + if (null != builder.userAgent) { + return builder.userAgent; + } else { + // Try to get default agent to not loose environment definitions. + final String agent = System.getProperty("http.agent"); + + if (null != agent) { + Matcher m = Pattern.compile("(\\s\\(.*\\))").matcher(agent); + + if (m.find() && m.groupCount() > 0 && m.group(1).length() > 0) { + return USER_AGENT_PREFIX + m.group(1); + } + } + } + + return USER_AGENT_PREFIX; + } + + /** + * 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 + * List of HeaderProperty instances. + * + * @param soapAction the namespace with which to perform the call in. + * @param envelope the envelope the contains the information for the call. + * @return Headers returned by the web service as a List of + * HeaderProperty instances. + * @throws HttpResponseException an IOException when Http response code is different from 200 + * @throws IOException an IOException when XML Serialization fails or HTTP fails + * @throws XmlPullParserException an XmlPullParserException when XML Parse fails + */ + public Headers call(String soapAction, SoapEnvelope envelope) + throws IOException, XmlPullParserException { + return call(soapAction, envelope, null); + } + + /** + * 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 + * List of HeaderProperty 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 List of HeaderProperty headers to send with the SOAP request. + * @return Headers returned by the web service as a List of + * HeaderProperty instances. + * @throws HttpResponseException an IOException when Http response code is different from 200 + * @throws IOException an IOException when XML Serialization fails or HTTP fails + * @throws XmlPullParserException an XmlPullParserException when XML Parse fails + */ + public Headers call(String soapAction, SoapEnvelope envelope, Headers headers) + throws IOException, XmlPullParserException { + + if (soapAction == null) { + soapAction = "\"\""; + } + logger.fine("SoapAction: " + soapAction); + + MediaType contentType; + if (envelope.version == SoapSerializationEnvelope.VER12) { + contentType = MediaType.parse(Transport.CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8); + } else { + contentType = MediaType.parse(Transport.CONTENT_TYPE_XML_CHARSET_UTF_8); + } + logger.finer("ContentType: " + contentType); + + + byte[] requestData = createRequestData(envelope); + if (logger.getLevel().intValue() <= Level.FINEST.intValue()) { + logger.finest("Request Payload: " + new String(requestData, DEFAULT_CHARSET)); + } + + RequestBody body = RequestBody.create(contentType, requestData); + + Request.Builder builder = new Request.Builder() + .url(url) + .cacheControl(CacheControl.FORCE_NETWORK) + .post(body); + + builder.addHeader("User-Agent", userAgent); + + // 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 + if (envelope.version != SoapSerializationEnvelope.VER12) { + builder.addHeader("SOAPAction", soapAction); + } + + if (null != this.headers) { + for (int i = 0; i < this.headers.size(); i++) { + builder.addHeader(this.headers.name(i), this.headers.value(i)); + } + } + + if (null != headers) { + for (int i = 0; i < headers.size(); i++) { + builder.addHeader(headers.name(i), headers.value(i)); + } + } + + final Request request = builder.build(); + logger.finer("Request Headers: " + request.headers().toString()); + + final Response response = client.newCall(request).execute(); + ResponseBody responseBody = null; + try { + if (response == null) { + throw new HttpResponseException("Null response.", -1); + } + + responseBody = response.body(); + if (responseBody == null) { + throw new HttpResponseException("Null response body.", response.code()); + } + + final Headers responseHeaders = response.headers(); + logger.finer("Response Headers: " + responseHeaders.toString()); + + if (logger.getLevel().intValue() <= Level.FINEST.intValue()) { + logger.finest("Response Payload (max first 32KB): " + response.peekBody(32 * 1024).string()); + } + + if (!response.isSuccessful()) { + throw new HttpResponseException("HTTP request failed, HTTP status: " + response.code(), + response.code(), responseHeaders); + } + + parseResponse(envelope, responseBody.byteStream()); + + return responseHeaders; + } catch (HttpResponseException e) { + if (null != responseBody) { // Try to get soap fault + try { + parseResponse(envelope, responseBody.byteStream()); + } catch (XmlPullParserException ignore) { + } + } + + throw e; + } finally { + if (null != responseBody) { + responseBody.close(); // Release resources.. + } + } + } + + /** + * Serializes the request. + */ + private byte[] createRequestData(SoapEnvelope envelope) + throws IOException { + final ByteArrayOutputStream bos = new ByteArrayOutputStream(8 * 1024); + final XmlSerializer xw = new KXmlSerializer(); + xw.setOutput(bos, DEFAULT_CHARSET); + envelope.write(xw); + xw.flush(); + bos.write('\r'); + bos.write('\n'); + bos.flush(); + return bos.toByteArray(); + } + + /** + * Sets up the parsing to hand over to the envelope to deserialize. + */ + private void parseResponse(SoapEnvelope envelope, InputStream is) + throws XmlPullParserException, IOException { + final XmlPullParser xp = new KXmlParser(); + xp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + xp.setInput(is, null); + envelope.parse(xp); + } + + public static class Builder { + private final HttpUrl url; + private Proxy proxy = null; + private int timeout = DEFAULT_TIMEOUT; + private String userAgent = null; + private Headers headers = null; + private OkHttpClient client = null; + private SSLSocketFactory sslSocketFactory = null; + private X509TrustManager trustManager = null; + private Authenticator authenticator = null; + private Authenticator proxyAuthenticator = null; + private boolean debug = false; + + /** + * Transport builder for OkHttp client. + * + * @param url the destination to POST SOAP data. + */ + public Builder(HttpUrl url) { + this.url = url; + } + + /** + * Transport builder for OkHttp client. + * + * @param url the destination to POST SOAP data. + */ + public Builder(String url) { + this.url = HttpUrl.parse(url); + } + + /** + * @param client User defined OkHttpClient + * @return builder chain + */ + public Builder client(OkHttpClient client) { + this.client = client; + return this; + } + + /** + * @param proxy Proxy server + * @return builder chain + */ + public Builder proxy(Proxy proxy) { + this.proxy = proxy; + return this; + } + + /** + * @param timeout Connection and Read timeout + * @return builder chain + */ + public Builder timeout(int timeout) { + this.timeout = timeout; + return this; + } + + /** + * @param userAgent User defined http.agent + * @return builder chain + */ + public Builder userAgent(String userAgent) { + this.userAgent = userAgent; + return this; + } + + /** + * @param headers HTTP headers those will be added as default. + * @return builder chain + */ + public Builder headers(Headers headers) { + this.headers = headers; + return this; + } + + /** + * SSLSocketFactory and X509TrustManager objects to verify SSL/TLS certificate. + *

+ * Example: + * + * KeyStore trustStore = KeyStore.getInstance("BKS"); + * InputStream trustStoreStream = getResources().openRawResource(R.raw.truststore); + * trustStore.load(trustStoreStream, null); + * trustStoreStream.close(); + * + * TrustManagerFactory trustManagerFactory = + * TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + * trustManagerFactory.init(trustStore); + * X509TrustManager x509TrustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0]; + * + * KeyManagerFactory keyManagerFactory = + * KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + * keyManagerFactory.init(trustStore, null); // BouncyCastle keystore don't + * // require password to load certificates. + * + * SSLContext sslContext = SSLContext.getInstance("TLS"); + * sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + * + * SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + * OkHttpTransport transport = new OkHttpTransport.Builder(webServiceUrl) + * .sslSocketFactory(sslSocketFactory, x509TrustManager) + * + * + * @param sslSocketFactory {@link SSLSocketFactory} object + * @param trustManager {@link X509TrustManager} object + * @return builder chain + */ + public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) { + this.sslSocketFactory = sslSocketFactory; + this.trustManager = trustManager; + return this; + } + + /** + * @param authenticator An implementation of {@link okhttp3.Authenticator} interface. + * @return builder chain + */ + public Builder authenticator(Authenticator authenticator) { + this.authenticator = authenticator; + return this; + } + + /** + * @param authenticator An implementation of {@link okhttp3.Authenticator} interface. + * @return builder chain + */ + public Builder proxyAuthenticator(Authenticator authenticator) { + this.proxyAuthenticator = authenticator; + return this; + } + + /** + * Don't use this in production. + * + * @param debug activate printing debug info. + * @return builder chain + */ + public Builder debug(boolean debug) { + this.debug = debug; + return this; + } + + /** + * @return OkHttpTransport object. + */ + public OkHttpTransport build() { + return new OkHttpTransport(this); + } + } +} diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/AuthenticatorException.java b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/AuthenticatorException.java new file mode 100644 index 00000000..7d9dea51 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/AuthenticatorException.java @@ -0,0 +1,7 @@ +package org.ksoap2.transport.authenticator; + +public class AuthenticatorException extends RuntimeException { + AuthenticatorException(String message) { + super(message); + } +} diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/AuthenticatorHelper.java b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/AuthenticatorHelper.java new file mode 100644 index 00000000..57035cb0 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/AuthenticatorHelper.java @@ -0,0 +1,14 @@ +package org.ksoap2.transport.authenticator; + +import okhttp3.Response; + +class AuthenticatorHelper { + static int responseCount(Response response) { + int result = 1; + while ((response = response.priorResponse()) != null) { + result++; + } + + return result; + } +} diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/BasicAuthenticator.java b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/BasicAuthenticator.java new file mode 100644 index 00000000..5e909147 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/BasicAuthenticator.java @@ -0,0 +1,65 @@ +package org.ksoap2.transport.authenticator; + +import okhttp3.*; + +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A basic authenticator implementation of {@link Authenticator} interface to use with OkHttpTransport. + */ +public class BasicAuthenticator implements Authenticator { + private static final String DEFAULT_CHARSET = "ISO-8859-1"; + private static Pattern charsetMatcher = Pattern.compile("(?i)charset=(?-i)\"([a-zA-Z0-9-]+)\""); + + private final String userName; + private final String password; + + /** + * @param userName User name + * @param password Password + */ + public BasicAuthenticator(String userName, String password) { + this.userName = userName; + this.password = password; + } + + /** + * @throws IllegalCharsetNameException If the given charset name is illegal + * @throws UnsupportedCharsetException If no support for the named charset is available + * in this instance of the Java virtual machine + */ + @Override + public Request authenticate(Route route, Response response) { + String charset = DEFAULT_CHARSET; + + List authHeaders = response.headers("WWW-Authenticate"); + if (authHeaders == null) { + return null; + } + + for (String authHeader : authHeaders) { + if (!authHeader.startsWith("Basic")) { + continue; + } + + if (AuthenticatorHelper.responseCount(response) > 3) { + throw new AuthenticatorException("Failed Basic Authentication."); + } + + final Matcher matcher = charsetMatcher.matcher(authHeader); + if (matcher.find()) { + charset = matcher.group(1); + } + + final String credential = Credentials.basic(userName, password, Charset.forName(charset)); + return response.request().newBuilder().header("Authorization", credential).build(); + } + + return null; + } +} diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/JCIFSEngine.java b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/JCIFSEngine.java new file mode 100644 index 00000000..a1b5f819 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/JCIFSEngine.java @@ -0,0 +1,51 @@ +package org.ksoap2.transport.authenticator; + +import jcifs.ntlmssp.NtlmFlags; +import jcifs.ntlmssp.Type1Message; +import jcifs.ntlmssp.Type2Message; +import jcifs.ntlmssp.Type3Message; +import jcifs.util.Base64; + +import java.io.IOException; + +/** + * Class taken from http://hc.apache.org/httpcomponents-client-ga/ntlm.html + */ +final class JCIFSEngine { + + private static final int TYPE_1_FLAGS = + NtlmFlags.NTLMSSP_NEGOTIATE_56 | + NtlmFlags.NTLMSSP_NEGOTIATE_128 | + NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 | + NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | + NtlmFlags.NTLMSSP_REQUEST_TARGET; + + static String generateType1Msg(final String domain, final String workstation) + throws JCIFSEngineException { + final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation); + return Base64.encode(type1Message.toByteArray()); + } + + static String generateType3Msg(final String username, final String password, + final String domain, final String workstation, final String challenge) + throws JCIFSEngineException { + Type2Message type2Message; + try { + type2Message = new Type2Message(Base64.decode(challenge)); + } catch (final IOException exception) { + throw new JCIFSEngineException("Invalid NTLM type 2 message", exception); + } + final int type2Flags = type2Message.getFlags(); + final int type3Flags = type2Flags + & ~(NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER); + final Type3Message type3Message = new Type3Message(type2Message, password, domain, + username, workstation, type3Flags); + return Base64.encode(type3Message.toByteArray()); + } + + private static class JCIFSEngineException extends IOException { + JCIFSEngineException(String message, Throwable cause) { + super(message, cause); + } + } +} diff --git a/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/NtlmAuthenticator.java b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/NtlmAuthenticator.java new file mode 100644 index 00000000..f6fbb8c4 --- /dev/null +++ b/ksoap2-okhttp/src/main/java/org.ksoap2/transport/authenticator/NtlmAuthenticator.java @@ -0,0 +1,60 @@ +package org.ksoap2.transport.authenticator; + +import okhttp3.*; + +import java.io.IOException; +import java.util.List; + +/** + * A ntlm authenticator implementation of {@link Authenticator} interface to use with OkHttpTransport. + */ +public class NtlmAuthenticator implements Authenticator { + private final String userName; + private final String password; + private final String ntDomain; + private final String ntWorkstation; + + /** + * @param userName User name + * @param password Password + * @param ntDomain Domain + * @param ntWorkstation Workstation + */ + public NtlmAuthenticator(final String userName, final String password, + final String ntDomain, final String ntWorkstation) { + this.userName = userName; + this.password = password; + this.ntDomain = ntDomain; + this.ntWorkstation = ntWorkstation; + } + + @Override + public Request authenticate(final Route route, final Response response) throws IOException { + final List authHeaders = response.headers("WWW-Authenticate"); + if (authHeaders == null) { + return null; + } + + boolean negotiate = false; + for (String authHeader : authHeaders) { + if (authHeader.equalsIgnoreCase("Negotiate")) { + negotiate = true; + } else if (negotiate && authHeader.equalsIgnoreCase("NTLM")) { + if (AuthenticatorHelper.responseCount(response) > 3) { + throw new AuthenticatorException("Failed NTLM Authentication."); + } + + final String type1Msg = JCIFSEngine.generateType1Msg(ntDomain, ntWorkstation); + return response.request().newBuilder().header("Authorization", "NTLM " + type1Msg).build(); + } else if (authHeader.startsWith("NTLM ")) { + final String challenge = authHeader.substring(5); + final String type3Msg = JCIFSEngine.generateType3Msg( + userName, password, ntDomain, ntWorkstation, challenge); + return response.request().newBuilder().header("Authorization", "NTLM " + type3Msg).build(); + } + } + + return null; + } + +} diff --git a/ksoap2-okhttp/src/main/resources/logging.properties b/ksoap2-okhttp/src/main/resources/logging.properties new file mode 100644 index 00000000..f05140b4 --- /dev/null +++ b/ksoap2-okhttp/src/main/resources/logging.properties @@ -0,0 +1,10 @@ +# "handlers" specifies a comma separated list of log Handler +# classes. These handlers will be installed during VM startup. +# Note that these classes must be on the system classpath. +# By default we only configure a ConsoleHandler. +handlers=java.util.logging.ConsoleHandler +# Default global logging level. +.level=ALL +# Limit the message that are printed on the console to FINEST and above. +java.util.logging.ConsoleHandler.level=FINEST +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter diff --git a/ksoap2-okhttp/src/test/java/org/ksoap2/serialization/MarshalFloatTest.java b/ksoap2-okhttp/src/test/java/org/ksoap2/serialization/MarshalFloatTest.java new file mode 100644 index 00000000..4b96dfdc --- /dev/null +++ b/ksoap2-okhttp/src/test/java/org/ksoap2/serialization/MarshalFloatTest.java @@ -0,0 +1,88 @@ +package org.ksoap2.serialization; + +import java.io.*; +import java.math.*; + +import org.junit.*; + +import org.ksoap2.*; +import org.ksoap2.transport.mock.*; +import org.xmlpull.v1.*; + +import static junit.framework.TestCase.*; + +public class MarshalFloatTest { + private static final String FLOAT_LABEL = "float"; + + private static final String FLOATING_POINT_VALUE = "12.0"; + + private MarshalFloat marshalFloat; + + @Before + public void setUp() throws Exception { + marshalFloat = new MarshalFloat(); + } + + @Test + public void testMarshalDateInbound() throws IOException, XmlPullParserException { + MockXmlPullParser mockXmlPullParser = new MockXmlPullParser(); + mockXmlPullParser.nextText = FLOATING_POINT_VALUE; + + Number floatingPointValue = (Number) marshalFloat.readInstance(mockXmlPullParser, null, FLOAT_LABEL, null); + assertTrue(floatingPointValue instanceof Float); + assertEquals(Float.valueOf(FLOATING_POINT_VALUE), floatingPointValue.floatValue(), 0.01f); + + floatingPointValue = (Number) marshalFloat.readInstance(mockXmlPullParser, null, "double", null); + assertTrue(floatingPointValue instanceof Double); + assertEquals(Double.valueOf(FLOATING_POINT_VALUE), floatingPointValue.doubleValue(), 0.01d); + + floatingPointValue = (Number) marshalFloat.readInstance(mockXmlPullParser, null, "decimal", null); + assertTrue(floatingPointValue instanceof BigDecimal); + assertEquals(new BigDecimal(FLOATING_POINT_VALUE).doubleValue(), floatingPointValue.doubleValue(), 0.01d); + + try { + floatingPointValue = (Number) marshalFloat.readInstance(mockXmlPullParser, null, "unknown type", null); + fail(); + } catch (RuntimeException e) { + assertNotNull(e.getMessage()); + } + + } + + @Test + public void testMarshalDateOutbound_Float() throws IOException { + MockXmlSerializer writer = new MockXmlSerializer(); + marshalFloat.writeInstance(writer, 12.0f); + assertEquals(FLOATING_POINT_VALUE, writer.getOutputText()); + } + + @Test + public void testMarshalDateOutbound_Double() throws IOException { + MockXmlSerializer writer = new MockXmlSerializer(); + marshalFloat.writeInstance(writer, 12.0d); + assertEquals(FLOATING_POINT_VALUE, writer.getOutputText()); + } + + @Test + public void testMarshalDateOutbound_Decimal() throws IOException { + MockXmlSerializer writer = new MockXmlSerializer(); + marshalFloat.writeInstance(writer, new BigDecimal(12.0d)); + assertEquals("12", writer.getOutputText()); + } + + @Test + public void testRegistration_moreIntegrationLike() throws IOException, XmlPullParserException { + MockXmlPullParser pullParser = new MockXmlPullParser(); + pullParser.nextText = FLOATING_POINT_VALUE; + + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + marshalFloat.register(envelope); + assertTrue(envelope.classToQName.containsKey(Float.class.getName())); + assertTrue(envelope.classToQName.containsKey(Double.class.getName())); + assertTrue(envelope.classToQName.containsKey(BigDecimal.class.getName())); + + Float floatingPointValue = (Float) envelope.readInstance(pullParser, envelope.xsd, FLOAT_LABEL, null); + assertEquals(Float.valueOf(FLOATING_POINT_VALUE), floatingPointValue, 0.01f); + } + +} diff --git a/ksoap2-okhttp/src/test/java/org/ksoap2/transport/OkHttpTransportTest.java b/ksoap2-okhttp/src/test/java/org/ksoap2/transport/OkHttpTransportTest.java new file mode 100644 index 00000000..e1529811 --- /dev/null +++ b/ksoap2-okhttp/src/test/java/org/ksoap2/transport/OkHttpTransportTest.java @@ -0,0 +1,75 @@ +package org.ksoap2.transport; + +import okhttp3.Headers; +import org.junit.Test; +import org.ksoap2.SoapEnvelope; +import org.ksoap2.SoapFault; +import org.ksoap2.serialization.PropertyInfo; +import org.ksoap2.serialization.SoapObject; +import org.ksoap2.serialization.SoapPrimitive; +import org.ksoap2.serialization.SoapSerializationEnvelope; + +import static org.junit.Assert.*; +import org.junit.Ignore; + +public class OkHttpTransportTest { + + @Ignore + @Test + public void testCallGlobalWeatherService() throws Throwable { + OkHttpTransport transport = + new OkHttpTransport.Builder("http://www.webservicex.net/globalweather.asmx") + .build(); + + SoapObject request = new SoapObject("http://www.webserviceX.NET", "GetWeather"); + request.addProperty(getStringPropertyInfoEnvelope("CountryName", "Turkey")); + request.addProperty(getStringPropertyInfoEnvelope("CityName", "Ankara")); + + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + envelope.dotNet = true; + envelope.setOutputSoapObject(request); + + Headers responseHeaders = transport.call("http://www.webserviceX.NET/GetWeather", envelope); + + assertNotNull(responseHeaders); + + SoapPrimitive response = (SoapPrimitive) envelope.getResponse(); + + assertNotNull(response); + + assertTrue(response.getValue().toString().length() > 0); + } + + @Ignore + @Test(expected = HttpResponseException.class) + public void testCallGlobalWeatherServiceForFault() throws Throwable { + OkHttpTransport transport = + new OkHttpTransport.Builder("http://www.webservicex.net/globalweather.asmx") + .build(); + + SoapObject request = new SoapObject("http://www.webserviceX.NET", "GetWeather"); + // Missing values should generate a SoapFault with 500 status + + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + envelope.dotNet = true; + envelope.setOutputSoapObject(request); + + try { + transport.call("http://www.webserviceX.NET/GetWeather", envelope); + } catch (HttpResponseException e) { + assertNotNull(envelope.bodyIn); + assertTrue(envelope.bodyIn instanceof SoapFault); + + throw e; + } + } + + private PropertyInfo getStringPropertyInfoEnvelope(String key, String value) { + PropertyInfo pi = new PropertyInfo(); + pi.setName(key); + pi.setValue(value); + pi.setType(value.getClass()); + + return pi; + } +} diff --git a/ksoap2-samples-axis/.gitignore b/ksoap2-samples-axis/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-samples-axis/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-samples-axis/pom.xml b/ksoap2-samples-axis/pom.xml index 4ee2d46c..fb3b071b 100644 --- a/ksoap2-samples-axis/pom.xml +++ b/ksoap2-samples-axis/pom.xml @@ -1,25 +1,36 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-samples-axis - ksoap2-samples-axis - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - com.google.code.ksoap2-android - ksoap2-midp - - + ksoap2-samples-axis + jar + ksoap2-samples-axis + + + + + + com.google.code.ksoap2-android + ksoap2-midp + ${project.version} + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + diff --git a/ksoap2-samples-axis/src/main/java/net/wessendorf/j2me/SoapDemo.java b/ksoap2-samples-axis/src/main/java/net/wessendorf/j2me/SoapDemo.java index 3382cd64..44d046bf 100644 --- a/ksoap2-samples-axis/src/main/java/net/wessendorf/j2me/SoapDemo.java +++ b/ksoap2-samples-axis/src/main/java/net/wessendorf/j2me/SoapDemo.java @@ -11,38 +11,38 @@ public class SoapDemo extends MIDlet implements CommandListener{ - + private Display display; - + Form mainForm = new Form ("Hello World WebService"); TextField nameField = new TextField ("Your name","",456,TextField.ANY); Command getCommand = new Command ("send", Command.SCREEN, 1); public SoapDemo () { - mainForm.append (nameField); - mainForm.addCommand (getCommand); - mainForm.setCommandListener (this); + mainForm.append (nameField); + mainForm.addCommand (getCommand); + mainForm.setCommandListener (this); } - + public void startApp() { display = Display.getDisplay (this); display.setCurrent (mainForm); } - + public void pauseApp() { } - + public void destroyApp(boolean unconditional) { } - + public void commandAction(Command c, Displayable s) { if (c == getCommand) { - final TextBox t = new TextBox("", "", 256, 0); - Thread thr = new Thread(){ - public void run() { - try { - + final TextBox t = new TextBox("", "", 256, 0); + Thread thr = new Thread(){ + public void run() { + try { + SoapObject client = new SoapObject("","getObject"); client.addProperty("name",nameField.getString()); @@ -64,8 +64,8 @@ public void run() { e.printStackTrace(); t.setString(e.getMessage()); } - }}; - thr.start(); + }}; + thr.start(); display.setCurrent(t); } else{ @@ -73,4 +73,4 @@ public void run() { notifyDestroyed(); } } -} \ No newline at end of file +} diff --git a/ksoap2-samples/.gitignore b/ksoap2-samples/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-samples/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-samples/pom.xml b/ksoap2-samples/pom.xml index bf666124..ad64582e 100644 --- a/ksoap2-samples/pom.xml +++ b/ksoap2-samples/pom.xml @@ -1,29 +1,41 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-samples - ksoap2-samples - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - com.google.code.ksoap2-android - ksoap2-j2se - - - com.google.code.ksoap2-android - ksoap2-midp - - + ksoap2-samples + jar + ksoap2-samples + + + + + + com.google.code.ksoap2-android + ksoap2-j2se + ${project.version} + + + com.google.code.ksoap2-android + ksoap2-midp + ${project.version} + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/AmazonDemo.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/AmazonDemo.java index 68c5b79c..7d575a17 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/AmazonDemo.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/AmazonDemo.java @@ -19,24 +19,24 @@ public class AmazonDemo extends MIDlet implements CommandListener, Runnable { - Display display; + Display display; Form mainForm = new Form("Amazon Sample"); - TextField tagField = new TextField("Developer-Tag", "", 64, TextField.ANY); + TextField tagField = new TextField("Developer-Tag", "", 64, TextField.ANY); TextField symbolField = new TextField("Keyword", "pattern", 64, TextField.ANY); - StringItem statusItem = new StringItem("Status", "idle"); - //TextField tagField = new TextField("") + StringItem statusItem = new StringItem("Status", "idle"); + //TextField tagField = new TextField("") // StringItem resultItem = new StringItem("", ""); static Command getCommand = new Command("Get", Command.SCREEN, 1); - static Command detailCommand = new Command("Details", Command.SCREEN, 1); - static Command newCommand = new Command("New", Command.SCREEN, 1); - static Command backCommand = new Command("Back", Command.BACK, 1); + static Command detailCommand = new Command("Details", Command.SCREEN, 1); + static Command newCommand = new Command("New", Command.SCREEN, 1); + static Command backCommand = new Command("Back", Command.BACK, 1); Vector resultVector; List resultList; - + public AmazonDemo() { - mainForm.append(tagField); + mainForm.append(tagField); mainForm.append(symbolField); mainForm.append(statusItem); mainForm.addCommand(getCommand); @@ -54,124 +54,125 @@ public void pauseApp() { public void destroyApp(boolean unconditional) { } - - public void run(){ - try { - // build request string - String symbol = symbolField.getString(); - - statusItem.setText("building request"); - - SoapObject rpc = - new SoapObject("urn:PI/DevCentral/SoapService", "KeywordSearchRequest"); - - - SoapObject ro = new SoapObject("urn:PI/DevCentral/SoapService", "KeywordRequest"); - - ro.addProperty("keyword", symbol.trim().toLowerCase()); - ro.addProperty("tag", "webservices-20"); - ro.addProperty("type", "lite"); - ro.addProperty("mode", "book"); - ro.addProperty("page", "1"); - ro.addProperty("devtag", tagField.getString()); - - rpc.addProperty("KeywordSearchRequest", ro); - + + public void run(){ + try { + // build request string + String symbol = symbolField.getString(); + + statusItem.setText("building request"); + + SoapObject rpc = + new SoapObject("urn:PI/DevCentral/SoapService", "KeywordSearchRequest"); + + + SoapObject ro = new SoapObject("urn:PI/DevCentral/SoapService", "KeywordRequest"); + + ro.addProperty("keyword", symbol.trim().toLowerCase()); + ro.addProperty("tag", "webservices-20"); + ro.addProperty("type", "lite"); + ro.addProperty("mode", "book"); + ro.addProperty("page", "1"); + ro.addProperty("devtag", tagField.getString()); + + rpc.addProperty("KeywordSearchRequest", ro); + /* - dog - 1 - book - webservices-20 - lite - your-dev-tag - xml - 1.0 + dog + 1 + book + webservices-20 + lite + your-dev-tag + xml + 1.0 */ - SoapSerializationEnvelope envelope = - new SoapSerializationEnvelope(SoapEnvelope.VER11); - - envelope.bodyOut = rpc; - - //resultItem.setLabel(symbol); - - HttpTransport ht = new HttpTransport("http://soap.amazon.com/onca/soap3"); - ht.debug = true; - - statusItem.setText("submitting request"); - - try{ - - ht.call(null, envelope); - - statusItem.setText("analyzing results..."); - - System.err.println (ht.responseDump); - - SoapObject result = (SoapObject) envelope.getResponse(); - - resultVector = (Vector) result.getProperty("Details"); //.getProperty("Details"); - - - resultList = new List("Result", List.IMPLICIT); - resultList.addCommand(newCommand); - resultList.addCommand(detailCommand); - resultList.setCommandListener(this); - - for(int i = 0; i < resultVector.size(); i++){ - SoapObject detail = (SoapObject) resultVector.elementAt(i); - resultList.append((String) detail.getProperty("ProductName"), null); - } - - display.setCurrent(resultList); - -// for(int i = 0; i < result.getPropertyCount()) - } - catch (SoapFault f) { -// e.printStackTrace(); -// System.err.println (ht.requestDump); -// System.err.println (ht.responseDump); - - statusItem.setText("Error (perhaps keyword not found): "+f.faultstring); - } - - - } - catch (Exception e) { - e.printStackTrace(); - statusItem.setText("Error: "+ e.toString()); - } - - } + SoapSerializationEnvelope envelope = + new SoapSerializationEnvelope(SoapEnvelope.VER11); + + envelope.bodyOut = rpc; + + //resultItem.setLabel(symbol); + + HttpTransport ht = new HttpTransport("http://soap.amazon.com/onca/soap3"); + ht.debug = true; + + statusItem.setText("submitting request"); + + try{ + + ht.call(null, envelope); + + statusItem.setText("analyzing results..."); + + System.err.println (ht.responseDump); + + SoapObject result = (SoapObject) envelope.getResponse(); + + resultVector = (Vector) result.getProperty("Details"); //.getProperty("Details"); + + + resultList = new List("Result", List.IMPLICIT); + resultList.addCommand(newCommand); + resultList.addCommand(detailCommand); + resultList.setCommandListener(this); + + for(int i = 0; i < resultVector.size(); i++){ + SoapObject detail = (SoapObject) resultVector.elementAt(i); + resultList.append((String) detail.getProperty("ProductName"), null); + } + + display.setCurrent(resultList); + +//for(int i = 0; i < result.getPropertyCount()) + } + catch (SoapFault f) { +//e.printStackTrace(); +//System.err.println (ht.requestDump); +//System.err.println (ht.responseDump); + + statusItem.setText("Error (perhaps keyword not found): "+f.faultstring); + } + + + } + catch (Exception e) { + e.printStackTrace(); + statusItem.setText("Error: "+ e.toString()); + } + + } public void commandAction(Command c, Displayable d) { - if(c == getCommand){ - new Thread(this).start(); - } - else if(c == newCommand){ - display.setCurrent(mainForm); - statusItem.setText("idle"); - } - else if(c == backCommand){ - display.setCurrent(resultList); - } - else { - int sel = resultList.getSelectedIndex(); - SoapObject details = (SoapObject) resultVector.elementAt(sel); - - Form detailForm = new Form("Details: "+resultList.getString(sel)); - detailForm.setCommandListener(this); - detailForm.addCommand(backCommand); - PropertyInfo pi = new PropertyInfo(); - for(int i = 0; i < details.getPropertyCount(); i++) { - details.getPropertyInfo(i, null, pi); - if(pi.name.toLowerCase().indexOf("url")==-1) - detailForm.append(new StringItem(pi.name, ""+details.getProperty(i))); - } - display.setCurrent(detailForm); - } + if(c == getCommand){ + new Thread(this).start(); + } + else if(c == newCommand){ + display.setCurrent(mainForm); + statusItem.setText("idle"); + } + else if(c == backCommand){ + display.setCurrent(resultList); + } + else { + int sel = resultList.getSelectedIndex(); + SoapObject details = (SoapObject) resultVector.elementAt(sel); + + Form detailForm = new Form("Details: "+resultList.getString(sel)); + detailForm.setCommandListener(this); + detailForm.addCommand(backCommand); + PropertyInfo pi = new PropertyInfo(); + for(int i = 0; i < details.getPropertyCount(); i++) { + details.getPropertyInfo(i, null, pi); + if(pi.name.toLowerCase().indexOf("url")==-1) { + detailForm.append(new StringItem(pi.name, ""+details.getProperty(i))); + } + } + display.setCurrent(detailForm); + } } } diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/AmazonSearchClient.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/AmazonSearchClient.java index 55fa189d..f41b6037 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/AmazonSearchClient.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/AmazonSearchClient.java @@ -27,7 +27,8 @@ public AmazonSearchClient() { registerObjects(envelope); - HttpTransportSE httpTransportSE = new HttpTransportSE("http://soap.amazon.com/onca/soap?Service=AWSECommerceService"); + HttpTransportSE httpTransportSE = + new HttpTransportSE("http://soap.amazon.com/onca/soap?Service=AWSECommerceService"); httpTransportSE.setXmlVersionTag(""); try { httpTransportSE.call("http://soap.amazon.com", envelope); diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BaseObject.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BaseObject.java index 3fb0e0a6..c95d50e4 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BaseObject.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BaseObject.java @@ -9,5 +9,4 @@ public abstract class BaseObject implements KvmSerializable { public BaseObject() { super(); } - -} \ No newline at end of file +} diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Book.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Book.java index 5d4bd38e..81a37db7 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Book.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Book.java @@ -61,4 +61,11 @@ public String toString() { return buffer.toString(); } + public String getInnerText() { + return null; + } + + public void setInnerText(String s) { + } + } diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookAttributes.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookAttributes.java index 9a2a98c7..1856abab 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookAttributes.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookAttributes.java @@ -89,5 +89,10 @@ public String toString() { } return buffer.toString(); } + public String getInnerText() { + return null; + } + public void setInnerText(String s) { + } } diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookItems.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookItems.java index 351e827f..4a00a082 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookItems.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/BookItems.java @@ -69,5 +69,10 @@ public synchronized String toString() { } return buffer.toString(); } + public String getInnerText() { + return null; + } + public void setInnerText(String s) { + } } diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/ItemSearchResponse.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/ItemSearchResponse.java index ac1f31fb..46b96a0f 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/ItemSearchResponse.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/ItemSearchResponse.java @@ -48,5 +48,10 @@ public void register(SoapSerializationEnvelope envelope) { new BookItems().register(envelope); new BookAttributes().register(envelope); } + public String getInnerText() { + return null; + } + public void setInnerText(String s) { + } } diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/LiteralArrayVector.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/LiteralArrayVector.java index 30cea909..8d2f391c 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/LiteralArrayVector.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/LiteralArrayVector.java @@ -1,49 +1,50 @@ -package org.ksoap2.samples.amazon.search.messages; - -import java.util.*; - -import org.ksoap2.serialization.*; - -public abstract class LiteralArrayVector extends Vector implements KvmSerializable { - - public void register(SoapSerializationEnvelope envelope, String namespace, String name) { - // using this.getClass() everywhere because .class doesn't - // exist on j2me - envelope.addMapping(namespace, name, this.getClass()); - registerElementClass(envelope, namespace); - } - - private void registerElementClass(SoapSerializationEnvelope envelope, String namespace) { - final Class elementClass = getElementClass(); - try { - if (elementClass.newInstance() instanceof KvmSerializable) - envelope.addMapping(namespace, "", elementClass); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) { - info.name = getItemDescriptor(); - info.type = getElementClass(); - } - - public Object getProperty(int index) { - return this; - } - - public int getPropertyCount() { - return 1; - } - - public void setProperty(int index, Object value) { - addElement(value); - } - - abstract protected Class getElementClass(); - - protected String getItemDescriptor() { - return "item"; - } - -} +package org.ksoap2.samples.amazon.search.messages; + +import java.util.*; + +import org.ksoap2.serialization.*; + +public abstract class LiteralArrayVector extends Vector implements KvmSerializable { + + public void register(SoapSerializationEnvelope envelope, String namespace, String name) { + // using this.getClass() everywhere because .class doesn't + // exist on j2me + envelope.addMapping(namespace, name, this.getClass()); + registerElementClass(envelope, namespace); + } + + private void registerElementClass(SoapSerializationEnvelope envelope, String namespace) { + final Class elementClass = getElementClass(); + try { + if (elementClass.newInstance() instanceof KvmSerializable) { + envelope.addMapping(namespace, "", elementClass); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) { + info.name = getItemDescriptor(); + info.type = getElementClass(); + } + + public Object getProperty(int index) { + return this; + } + + public int getPropertyCount() { + return 1; + } + + public void setProperty(int index, Object value) { + addElement(value); + } + + abstract protected Class getElementClass(); + + protected String getItemDescriptor() { + return "item"; + } + +} diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Request.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Request.java index f38c5e09..972069dd 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Request.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/amazon/search/messages/Request.java @@ -37,5 +37,10 @@ public void setProperty(int index, Object value) { public void register(SoapSerializationEnvelope envelope) { envelope.addMapping(NAMESPACE, "ItemSearchRequest", this.getClass()); } + public String getInnerText() { + return null; + } + public void setInnerText(String s) { + } } diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/quotes/StockQuoteDemo.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/quotes/StockQuoteDemo.java index 68bda385..55cc1744 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/quotes/StockQuoteDemo.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/quotes/StockQuoteDemo.java @@ -31,41 +31,40 @@ public void pauseApp() { public void destroyApp(boolean unconditional) { } - - public void run(){ - try { - // build request string - String symbol = symbolField.getString(); + public void run(){ + try { + // build request string + String symbol = symbolField.getString(); - SoapObject rpc = - new SoapObject("urn:xmethods-delayed-quotes", "getQuote"); + SoapObject rpc = + new SoapObject("urn:xmethods-delayed-quotes", "getQuote"); - rpc.addProperty("symbol", symbol); + rpc.addProperty("symbol", symbol); - SoapSerializationEnvelope envelope = - new SoapSerializationEnvelope(SoapEnvelope.VER10); + SoapSerializationEnvelope envelope = + new SoapSerializationEnvelope(SoapEnvelope.VER10); - envelope.bodyOut = rpc; + envelope.bodyOut = rpc; - resultItem.setLabel(symbol); + resultItem.setLabel(symbol); - HttpTransport ht = new HttpTransport("http://services.xmethods.net/soap"); - //ht.debug = true; - - ht.call("urn:xmethods-delayed-quotes#getQuote", envelope); - resultItem.setText("" + envelope.getResponse()); - } - catch (Exception e) { - e.printStackTrace(); - resultItem.setLabel("Error:"); - resultItem.setText(e.toString()); - } - - } + HttpTransport ht = new HttpTransport("http://services.xmethods.net/soap"); + //ht.debug = true; + + ht.call("urn:xmethods-delayed-quotes#getQuote", envelope); + resultItem.setText("" + envelope.getResponse()); + } + catch (Exception e) { + e.printStackTrace(); + resultItem.setLabel("Error:"); + resultItem.setText(e.toString()); + } + + } public void commandAction(Command c, Displayable d) { - new Thread(this).start(); + new Thread(this).start(); } /** for me4se */ diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/LiteralArrayVector.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/LiteralArrayVector.java index 9495a50d..6358ae17 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/LiteralArrayVector.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/LiteralArrayVector.java @@ -1,49 +1,50 @@ -package org.ksoap2.samples.soccer; - -import java.util.*; - -import org.ksoap2.serialization.*; - -public abstract class LiteralArrayVector extends Vector implements KvmSerializable { - - public void register(SoapSerializationEnvelope envelope, String namespace, String name) { - // using this.getClass() everywhere because .class doesn't - // exist on j2me - envelope.addMapping(namespace, name, this.getClass()); - registerElementClass(envelope, namespace); - } - - private void registerElementClass(SoapSerializationEnvelope envelope, String namespace) { - final Class elementClass = getElementClass(); - try { - if (elementClass.newInstance() instanceof KvmSerializable) - envelope.addMapping(namespace, "", elementClass); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) { - info.name = getItemDescriptor(); - info.type = getElementClass(); - } - - public Object getProperty(int index) { - return this; - } - - public int getPropertyCount() { - return 1; - } - - public void setProperty(int index, Object value) { - addElement(value); - } - - abstract protected Class getElementClass(); - - protected String getItemDescriptor() { - return "item"; - } - -} +package org.ksoap2.samples.soccer; + +import java.util.*; + +import org.ksoap2.serialization.*; + +public abstract class LiteralArrayVector extends Vector implements KvmSerializable { + + public void register(SoapSerializationEnvelope envelope, String namespace, String name) { + // using this.getClass() everywhere because .class doesn't + // exist on j2me + envelope.addMapping(namespace, name, this.getClass()); + registerElementClass(envelope, namespace); + } + + private void registerElementClass(SoapSerializationEnvelope envelope, String namespace) { + final Class elementClass = getElementClass(); + try { + if (elementClass.newInstance() instanceof KvmSerializable) { + envelope.addMapping(namespace, "", elementClass); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) { + info.name = getItemDescriptor(); + info.type = getElementClass(); + } + + public Object getProperty(int index) { + return this; + } + + public int getPropertyCount() { + return 1; + } + + public void setProperty(int index, Object value) { + addElement(value); + } + + abstract protected Class getElementClass(); + + protected String getItemDescriptor() { + return "item"; + } + +} diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/StadiumNamesResult.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/StadiumNamesResult.java index b183711f..f7451667 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/StadiumNamesResult.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/StadiumNamesResult.java @@ -16,5 +16,10 @@ protected String getItemDescriptor() { protected Class getElementClass() { return PropertyInfo.STRING_CLASS; } + public String getInnerText() { + return null; + } + public void setInnerText(String s) { + } } diff --git a/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/WorldCupSoccer2006Client.java b/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/WorldCupSoccer2006Client.java index a64f5ac2..a7bc1f96 100644 --- a/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/WorldCupSoccer2006Client.java +++ b/ksoap2-samples/src/main/java/org/ksoap2/samples/soccer/WorldCupSoccer2006Client.java @@ -52,7 +52,7 @@ private void createWrappingResultTemplate(SoapSerializationEnvelope envelope) { // contained objects to their classes. SoapObject template = new SoapObject(NAMESPACE, "StadiumNamesResponse"); - template.addProperty(info, "not important what this is"); + template.addProperty(info); envelope.addTemplate(template); } diff --git a/ksoap2-servlet/.gitignore b/ksoap2-servlet/.gitignore deleted file mode 100644 index 7f3abbd0..00000000 --- a/ksoap2-servlet/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Project output -bin/ -target*/ -*.log - -# Project config files -.settings/ -.project -.classpath - diff --git a/ksoap2-servlet/pom.xml b/ksoap2-servlet/pom.xml index 86bf53ef..6aaa7d66 100644 --- a/ksoap2-servlet/pom.xml +++ b/ksoap2-servlet/pom.xml @@ -1,33 +1,44 @@ + - 4.0.0 - - - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - + 4.0.0 - ksoap2-servlet - ksoap2-servlet - jar - - + + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + - - - com.google.code.ksoap2-android - ksoap2-base - + ksoap2-servlet + jar - - servletapi - servlet-api - 2.4 - jar - compile - - + ksoap2-servlet + + + + + com.google.code.ksoap2-android + ksoap2-base + ${project.version} + + + + javax.servlet + servlet-api + 2.4 + jar + compile + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + diff --git a/ksoap2-servlet/src/main/java/org/ksoap2/servlet/SoapServlet.java b/ksoap2-servlet/src/main/java/org/ksoap2/servlet/SoapServlet.java index c01cba6c..4cb6f591 100644 --- a/ksoap2-servlet/src/main/java/org/ksoap2/servlet/SoapServlet.java +++ b/ksoap2-servlet/src/main/java/org/ksoap2/servlet/SoapServlet.java @@ -64,8 +64,9 @@ public class SoapServlet extends HttpServlet { * servlet itself is returned. */ protected Object getInstance(HttpServletRequest request) { - if (request.getPathInfo() == null) + if (request.getPathInfo() == null) { return this; + } Object result = instanceMap.get(request.getPathInfo()); return (result != null) ? result : this; } @@ -104,8 +105,9 @@ public void publishInstance(String path, Object instance) { public void publishMethod(Class service, String namespace, String name, PropertyInfo[] parameters) { SoapObject template = new SoapObject(namespace, name); - for (int i = 0; i < parameters.length; i++) - template.addProperty(parameters[i], null); + for (int i = 0; i < parameters.length; i++) { + template.addProperty(parameters[i]); + } envelope.addTemplate(template); } @@ -199,7 +201,8 @@ public void doPost(HttpServletRequest req, HttpServletResponse res) throws Servl res.flushBuffer(); } - protected SoapObject invoke(Object service, SoapObject soapReq) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + protected SoapObject invoke(Object service, SoapObject soapReq) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { String name = soapReq.getName(); Class types[] = new Class[soapReq.getPropertyCount()]; Object[] args = new Object[soapReq.getPropertyCount()]; @@ -217,9 +220,9 @@ protected SoapObject invoke(Object service, SoapObject soapReq) throws NoSuchMet Object result = method.invoke(service, args); System.out.println("result:" + result); SoapObject response = new SoapObject(soapReq.getNamespace(), name + "Response"); - if (result != null) + if (result != null) { response.addProperty("return", result); + } return response; } - } diff --git a/mvnw b/mvnw new file mode 100755 index 00000000..34d9dae8 --- /dev/null +++ b/mvnw @@ -0,0 +1,305 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.bat b/mvnw.bat new file mode 100644 index 00000000..7ca42b99 --- /dev/null +++ b/mvnw.bat @@ -0,0 +1,177 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto chkMHome + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:chkMHome +if not "%M2_HOME%"=="" goto valMHome + +SET "M2_HOME=%~dp0.." +if not "%M2_HOME%"=="" goto valMHome + +echo. +echo Error: M2_HOME not found in your environment. >&2 +echo Please set the M2_HOME variable in your environment to match the >&2 +echo location of the Maven installation. >&2 +echo. +goto error + +:valMHome + +:stripMHome +if not "_%M2_HOME:~-1%"=="_\" goto checkMCmd +set "M2_HOME=%M2_HOME:~0,-1%" +goto stripMHome + +:checkMCmd +if exist "%M2_HOME%\bin\mvn.cmd" goto init + +echo. +echo Error: M2_HOME is set to an invalid directory. >&2 +echo M2_HOME = "%M2_HOME%" >&2 +echo Please set the M2_HOME variable in your environment to match the >&2 +echo location of the Maven installation >&2 +echo. +goto error +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +for %%i in ("%M2_HOME%"\boot\plexus-classworlds-*) do set CLASSWORLDS_JAR="%%i" + +set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.home=%M2_HOME%" "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 00000000..77b451d8 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,172 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + ) + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index cb9c6203..76e9dae3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,345 +1,313 @@ + - 4.0.0 + 4.0.0 - com.google.code.ksoap2-android - ksoap2-parent - 2.5-SNAPSHOT - pom + + com.simpligility.maven + progressive-organization-pom + 7.0.0 + - ksoap2-parent - - + com.google.code.ksoap2-android + ksoap2-parent + 3.6.5-SNAPSHOT + pom - http://code.google.com/p/ksoap2-android/ - 2002 + ksoap2-android Project + A lightweight and efficient SOAP library for the Android platform. + http://simpligility.github.io/ksoap2-android/ + 2002 + + + MIT and others + http://simpligility.github.io/ksoap2-android/license-information.html + + - - scm:git:git://github.com/karlmdavis/ksoap2-android.git - - scm:git:git@github.com:karlmdavis/ksoap2-android.git - - http://github.com/karlmdavis/ksoap2-android/tree/master - + + + Manfred Moser + manfred@simpligility.com + simpligility technologies inc. + http://www.simpligility.com + + + Many others + https://github.com/simpligility/ksoap2-android/graphs/contributors + + - - Google Code - http://code.google.com/p/ksoap2-android/issues/list - + + 3.1.1 + - - ksoap2-base - ksoap2-android - ksoap2-android-assembly - ksoap2-extras - ksoap2-j2se - ksoap2-midp - ksoap2-samples - ksoap2-samples-axis - ksoap2-servlet - + + build-tools + ksoap2-base + ksoap2-android + ksoap2-android-assembly + ksoap2-extras + ksoap2-extra-ntlm + ksoap2-j2se + ksoap2-midp + ksoap2-samples + ksoap2-samples-axis + ksoap2-servlet + ksoap2-jsoup + ksoap2-okhttp + - - - false - googlecode - svn:https://ksoap2-android.googlecode.com/svn/m2-repo - - - - - googlecode-ksoap2-android - googlecode-ksoap2-android - http://ksoap2-android.googlecode.com/svn/m2-repo - - - - - googlecode-ksoap2-android - googlecode-ksoap2-android - http://ksoap2-android.googlecode.com/svn/m2-repo - - + + scm:git:git://github.com/simpligility/ksoap2-android.git + scm:git:git@github.com:simpligility/ksoap2-android.git + http://github.com/simpligility/ksoap2-android/tree/master + HEAD + + + GitHub + https://github.com/simpligility/ksoap2-android/issues + + + Travis + https://travis-ci.org/simpligility/ksoap2-android + + + + ossrh + https://oss.sonatype.org/content/repositories/ksoap2-android-releases/ + + + ossrh + https://oss.sonatype.org/content/repositories/ksoap2-android-snapshots/ + + + github + scm:git:ssh://git@github.com/simpligility/ksoap2-android.git + + - - - - release - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - test-jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - - - + + UTF-8 + - - - - com.google.code.ksoap2-android - ksoap2-base - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-base - ${project.version} - test-jar - test - + + + + ossrh + https://oss.sonatype.org/content/repositories/ksoap2-android-releases/ + + + + + ossrh + https://oss.sonatype.org/content/repositories/ksoap2-android-releases/ + + - - com.google.code.ksoap2-android - ksoap2-android - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-android - ${project.version} - test-jar - test - + + + + net.sourceforge.kxml + kxml + 2.2.4 + jar + compile + - - com.google.code.ksoap2-android - ksoap2-extras - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-extras - ${project.version} - test-jar - test - + + net.sourceforge.kobjects + kobjects-j2me + 0.0-SNAPSHOT-20040926-2 + jar + compile + - - com.google.code.ksoap2-android - ksoap2-j2se - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-j2se - ${project.version} - test-jar - test - + + net.sourceforge.me4se + me4se + 2.1.4-SNAPSHOT-20040926 + jar + compile + - - com.google.code.ksoap2-android - ksoap2-midp - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-midp - ${project.version} - test-jar - test - + + junit + junit + 4.12 + jar + test + - - com.google.code.ksoap2-android - ksoap2-samples - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-samples - ${project.version} - test-jar - test - + + com.squareup.okhttp3 + okhttp-urlconnection + 3.12.1 + + + + + + + false + src/main/java + + + ** + + + **/*.java + + + + src/main/resources + + + + + src/test/resources + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + com.google.code.ksoap2-android + build-tools + ${project.version} + + + + simpligility/checkstyle.xml + true + + + + process-sources + + check + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + + + org.apache.maven.plugins + maven-release-plugin + + true + @{project.version} + + clean install + false + -Prelease + deploy + + + + org.apache.maven.plugins + maven-site-plugin + + true + + + + org.asciidoctor + asciidoctor-maven-plugin + 1.5.7.1 + + + + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + ${project.scm.developerConnection} + gh-pages + ${project.reporting.outputDirectory} + + + + scm-publish + site-deploy + + publish-scm + + + + + + + - - com.google.code.ksoap2-android - ksoap2-samples-axis - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-samples-axis - ${project.version} - test-jar - test - + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + issue-management + ci-management + + + + + + - - - com.google.code.ksoap2-android - ksoap2-servlet - ${project.version} - jar - compile - - - com.google.code.ksoap2-android - ksoap2-servlet - ${project.version} - test-jar - test - - - - net.sourceforge.kxml - kxml - 2.2.4 - jar - compile - - - - net.sourceforge.kobjects - kobjects-j2me - 0.0-SNAPSHOT-20040926-2 - jar - compile - - - - net.sourceforge.me4se - me4se - 2.1.4-SNAPSHOT-20040926 - jar - compile - - - - junit - junit - 3.8.1 - jar - test - - - - - - - - src/main/java - src/test/java - - - false - src/main/java - - - ** - - - **/*.java - - - - src/main/resources - - - - - src/test/resources - - - - - org.jvnet.wagon-svn - wagon-svn - 1.9 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.6 - 1.6 - - - - org.apache.maven.plugins - maven-release-plugin - 2.0 - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.2 - - - - true - - clean install - false - -Prelease - - - - org.apache.maven.plugins - maven-scm-plugin - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.2 - - - - - - + + + release + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + none + + + + attach-javadocs + + jar + + + + + + + + diff --git a/src/site/asciidoc/changelog.adoc b/src/site/asciidoc/changelog.adoc new file mode 100644 index 00000000..b50565f2 --- /dev/null +++ b/src/site/asciidoc/changelog.adoc @@ -0,0 +1,479 @@ +== Changelog + +The commit log is available at https://github.com/mosabua/ksoap2-android/commits/ + +=== 3.6.4 Release, 2019-03-07 + +* upgrade to okhttp 3.12.1 +** see https://github.com/simpligility/ksoap2-android/pull/127 +** contributed by Isaac Pateau https://github.com/zaclimon and Manfred Moser http://www.simpligility.com +* updated Maven wrapper +** contributed by Manfred Moser http://www.simpligility.com +* added current release version to default HTTP header user agetnt string +** see https://github.com/simpligility/ksoap2-android/commit/e9e57231ac5fb683f6df5dffbbde3383c2d789bb +** fixes https://github.com/simpligility/ksoap2-android/issues/120 +** contributed by Manfred Moser http://www.simpligility.com +* Removed dead link to wsdl2code from site nav +** contributed by Manfred Moser http://www.simpligility.com +* Updated parent pom version for newer plugins +** contributed by Manfred Moser http://www.simpligility.com + + +=== 3.6.3 Release, 2018-11-26 + +* Differentiating read and connection timeout +** see https://github.com/simpligility/ksoap2-android/pull/124 +* Added in okhttp support module into release +** see https://github.com/simpligility/ksoap2-android/pull/121 +** contributed by https://github.com/canyapan +* Removed dep mgt + +=== 3.6.2 Release, 2016-10-08 + +* Accept 202 http status code +** see https://github.com/simpligility/ksoap2-android/pull/102 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +* Allow to specify an existing OkHttpClient instance for transport +** see https://github.com/simpligility/ksoap2-android/pull/99 +** contributed by https://github.com/rob-X1 +* Changed site publishing to use scm-publish +** contributed by Manfred Moser http://www.simpligility.com + +=== 3.6.1 Release, 2016-05-24 + +* New transport and connection classes using OKHttp +** see https://github.com/simpligility/ksoap2-android/pull/83 +** contributed by Nicola Beghin https://github.com/nicolabeghin +* Updated junit and maven plugin versions + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.6.0 Release, 2015-10-15 + +* Added extensions which allows to customize soap message +** see https://github.com/simpligility/ksoap2-android/pull/74 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +** minor API incompatibility triggered minor version update to 3.6.0 + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.5.0 Release, 2015-09-09 + +* Updated Java language level to 1.5 +** see https://github.com/mosabua/ksoap2-android/commit/ed556eb35515d59e47174b1dd1b66d163212d2f5 +** contributed by Manfred Moser http://www.simpligility.com +* Fixed https connection with proxy +** see https://github.com/mosabua/ksoap2-android/pull/59 +** contributed by João Vitor P. Moraes https://github.com/jvlppm +* Store all http headers from the response in HttpResponseException? +** see https://github.com/mosabua/ksoap2-android/pull/61 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +* Support for namespace extensions +** see https://github.com/mosabua/ksoap2-android/pull/62 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +* Site migration to github +** contributed by Manfred Moser http://www.simpligility.com +* Maven repository migration to Sonatype +** contributed by Manfred Moser http://www.simpligility.com +** and Sonatype http://www.sonatype.com +* Updated and reworded all documentation for Maven/asciidoc powered site +** contributed by Manfred Moser http://www.simpligility.com +* Adapted project for changed release process +** contributed by Manfred Moser http://www.simpligility.com +* Improved NTLM transport +** see https://github.com/simpligility/ksoap2-android/pull/69 +** contributed by Johan Pelgrim http://www.codestone.nl/ +** see https://github.com/simpligility/ksoap2-android/pull/69 +** contributed by Can Yapan https://www.canyapan.com/ + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.4.0 Release, 2015-01-07 + +* Support for different namespaces and pre** fixes for attribute values, in case the value and the attribute are not in the same namespace. +** see https://github.com/mosabua/ksoap2-android/pull/53 +** contributed by chelala https://github.com/chelala +* Updated parent pom version for plugin version control +** contributed by Manfred Moser http://www.simpligility.com +* Support upper or lowercase for tags in soapfault +** see https://github.com/mosabua/ksoap2-android/pull/57 +** contributed by Omar Hussein https://github.com/satansly +* Addition of methods to improve attributes handling and inner text for tags +** see https://github.com/mosabua/ksoap2-android/pull/58 +** contributed by Omar Hussein https://github.com/satansly + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.3.0 Release, 2014-05-09 + +* Prevent NPE when getting property value +** see https://github.com/mosabua/ksoap2-android/pull/50 +** contributed by https://github.com/Islandman93 +* Fix to allow overriding SSLSocketFactory in ServiceConnection? +** see https://github.com/mosabua/ksoap2-android/pull/52 +** fixes issue 189 +** contributed by https://github.com/yousifucv +* Added feature to control a null value representation in SOAP message +** see https://github.com/mosabua/ksoap2-android/pull/51 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.2.0 Release, 2014-02-23 + +* Feature to allow skipping of properties with null value and not render them in the output xml at all +** see https://github.com/mosabua/ksoap2-android/pull/42 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +* Enable SoapSerializationEnvelope? to serialize attributes from any class that inherits from AttributeContainer?, not just SoapObject? +** see https://github.com/mosabua/ksoap2-android/pull/43 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +* Simplification for extending SoapSerializationEnvelope? +** see https://github.com/mosabua/ksoap2-android/pull/44 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +* Explicitly disconnecting serviceconnection to avoid issues with android keeping connection and trying to reconnect +** fixes issue 173 +** see https://github.com/mosabua/ksoap2-android/pull/47 +** contributed by https://github.com/Islandman93 +* Added interface HasAttributes? to allow different classes to have attributes (used for Vector now) +** see https://github.com/mosabua/ksoap2-android/pull/48 +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com +* Support for multi dimensional arrays for RPC encoded services +** see https://github.com/mosabua/ksoap2-android/pull/49/files +** contributed by https://github.com/robocik, Quasar Development from http://easywsdl.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.1.1 Release, 2013-11-29 + +* Making SoapPrimitive? more open and flexibile for reuse +** see commits around https://github.com/mosabua/ksoap2-android/commit/320c2560444cedfbca5be894750f0239eebde44d +** contributed by Sergey Kolebanov and Manfred Moser + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.1.0 Release, 2013-10-24 + +* SoapFault? parsing fix for responses with HTTP 500 response codes +** see https://github.com/mosabua/ksoap2-android/pull/38 +** contributed by Nico du Plessis http://nicoduplessis.com/ +* Provide file output stream instead of byte array if a file is created in HttpTransportSE +** see https://github.com/mosabua/ksoap2-android/pull/37 +** contributed by https://github.com/joschi70 +* Easier way of getting Http Response Code on Call() when response code != 200 +** see https://github.com/mosabua/ksoap2-android/pull/40 +** contributed by JBay Solutions https://github.com/syshex +* Fixed logic around ignoring connections closure +** see https://github.com/mosabua/ksoap2-android/commit/7c51bfb3da66d2748cc628ab8cd4a94aac23925f +** contributed by Manfred Moser http://www.simpligility.com +* Fixed logic around ignoring connections closure +** see https://github.com/mosabua/ksoap2-android/commit/7c51bfb3da66d2748cc628ab8cd4a94aac23925f +** contributed by Manfred Moser http://www.simpligility.com +* Removed connection close header, since it has been causing issues for users +** see https://github.com/mosabua/ksoap2-android/commit/c9b810a40f7c3f4843181f1dc024d62c702249ae +** contributed by Manfred Moser http://www.simpligility.com +* Updated parent pom, set to require Maven 3.1.1 and added travis ci build +** contributed by Manfred Moser http://www.simpligility.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.0.0 Release, 2013-03-05 + +* Added support to stream response into a file rather than parsing it +** see issue 137 +** contributed by Manfred Moser http://www.simpligility.com +* Removed duplicate variables hiding super class variable to expose access to timeout +** see https://github.com/mosabua/ksoap2-android/pull/34 +** contributed by Anatoliy Shuba, https://github.com/AShuba +* Modification to provide HTTP status information +** see https://github.com/mosabua/ksoap2-android/pull/32 +** contributed by https://github.com/baldheadedguy steighton@pointinside.com +* Disabled getting namespace from mapping and rather get correct type from response +** fixes issue 75 +** see https://github.com/mosabua/ksoap2-android/pull/33 +** contributed by Antonio Vila Juarez https://github.com/antoniov72 +* Clean up of transports and service connection usage +** see https://github.com/mosabua/ksoap2-android/pull/35 +** contributed by Anatoliy Shuba, https://github.com/AShuba + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.0.0-RC.4 Release, 2012-11-12 + +* Added BufferedInputStream? to wrap the InputStream? in transports +** should fix issue 82 +** see https://github.com/mosabua/ksoap2-android/pull/31 +* Add support for Proxy Configuration using HttpsTransportSE +** fixes issue 140 +** contributed by Manfred Moser http://www.simpligility.com +* Release process +** contributed by Manfred Moser http://www.simpligility.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.0.0-RC.3 Release, 2012-11-06 + +* Connection keep-alive or close Fix +** fixes issue 132 +** see https://github.com/mosabua/ksoap2-android/pull/30 +** contributed by Jose Castellanos Molina https://github.com/matlock08 + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.0.0-RC.2 Release, 2012-10-22 + +* Gzip stream workaround for Android 2.3 +** see https://github.com/mosabua/ksoap2-android/pull/26 +** contributed by Vadim Kotov +* SOAP envelope encoding synced with HTTP request Content-Type attribute +** see https://github.com/mosabua/ksoap2-android/pull/28/ +** contributed by Anatoliy Shuba, https://github.com/AShuba +* Fix gzipped error streams +** see https://github.com/mosabua/ksoap2-android/pull/27 +** fixes issue 131 +** contributed by Wesley Wiser, https://github.com/wesleywiser +* Close connection in transport +** see https://github.com/mosabua/ksoap2-android/pull/29 +** fixes issue 133 +** contributed by Maziz Eza https://github.com/MazizEsa +* Plugin updates and release process +** contributed by Manfred Moser http://www.simpligility.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 3.0.0-RC.1 Release, 2012-07-19 + +* fix for gzip support on servers that use lower case header properties +** see discussion in https://github.com/mosabua/ksoap2-android/pull/17 +* improved honoring of implicitTypes flag +** fixes issue 66 +** contributed by Anatoliy Shuba, https://github.com/AShuba +* improved access to service connection from transport classes +** see https://github.com/mosabua/ksoap2-android/pull/22 +** contributed by https://github.com/domenukk +* changed method name! +* removed all deprecated methods causing version to rev to 2.7.0, decided to do a RC.1 first though +** contributed by Manfred Moser http://www.simpligility.com +* optimized buffer length of requests +** contributed by Jose Castellanos Molina https://github.com/matlock08 +** see https://github.com/mosabua/ksoap2-android/pull/24 +* added module with support for NTLM support +** contributed by Manfred Moser http://www.simpligility.com based off contribution on the mailing list + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.6.5 Release, 2012-05-31 + +* Gzip encoding support +** fixes issue 103 +** see https://github.com/mosabua/ksoap2-android/pull/17 +** contributed by Anatoliy Shuba, https://github.com/AShuba +* newInstance() on SoapObject? modifies original instance fixed +** fixes issue 99 +** see https://github.com/mosabua/ksoap2-android/pull/18 +** contributed by Jose Castellanos Molina https://github.com/matlock08 +* removed redundant opening of connection in HttpTransportSE +** fixes issue 122 +** see https://github.com/mosabua/ksoap2-android/pull/20 +** contributed by Jose Castellanos Molina https://github.com/matlock08 + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.6.4 Release, 2012-05-01 + +* Skip unknown properties instead of throwing a RuntimeException? +use avoidExceptionForUnknownProperty property to activate +** see https://github.com/mosabua/ksoap2-android/pull/13 +** contributed by Nikolay Ivanets https://github.com/StenaviN +** somehow got lost in git merges, reapplied by Manfred Moser, , http://www.simpligility.com +* Fix to avoid inner class warning +** fixes issue 71 +** see https://github.com/mosabua/ksoap2-android/pull/16 +** contributed by Sergej Koščejev https://github.com/sergej-koscejev +* Made SoapObject#getPropertyInfo?() work for nested SoapObjects? +** fixes issue 117 +** see https://github.com/mosabua/ksoap2-android/pull/15 +** contributed by Sergej Koščejev https://github.com/sergej-koscejev +* Proper behaviour for getPropertySafelyAsString in case of null arguments +** fixes second part of issue 94 +** contributed by Manfred Moser, http://www.simpligility.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.6.3 Release, 2012-04-10 + +* Ensure that attributes on SoapPrimitives? are serialized out correctly and not list +** fixes issue 112 +** see https://github.com/mosabua/ksoap2-android/commit/f0e23aed58d2b8d0aabc4ae2436a2dc8c4e036bc +** contributed by Manfred Moser, http://www.simpligility.com +* Allow to set the SSLFactory for a https connection, essentially allow using self signed certificates +** see https://github.com/mosabua/ksoap2-android/pull/14 +** contributed by Frangiskos Sigalas https://github.com/silme +* Forcing code style on test code +** contributed by Manfred Moser, http://www.simpligility.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.6.2 Release, 2012-03-19 + +* convenience methods in SoapObject? to get primitive data without the anyType +** fixes issue 50 +** contributed by Konrad Barth https://github.com/ictoain +* Fix for nested soaps producing correct xml in serialization +** see https://github.com/mosabua/ksoap2-android/pull/12 +** contributed by Andrew Oppenlander http://themented.com +* Loss of data type in serialization fixed so that request produced is the same as for + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.6.0 release + +** see https://github.com/mosabua/ksoap2-android/commit/583e7ea839ea58cd577357e93b7232162d127599 +** see https://github.com/mosabua/ksoap2-android/commit/80d70289dc59686a09504ec1be4dc5a6bc9871f6 +** see https://github.com/mosabua/ksoap2-android/commit/895cac1a1072704238760fe401a2b72616ea8938 +** contributed by Manfred Moser, http://www.simpligility.com +* introduced checkstyle usage to force some common rules to avoid merge problems and problems with github display and also cleaned up a bunch of code to follow rules +** see https://github.com/mosabua/ksoap2-android/commit/d4e4bb597269dd9eaf5c85dc4bb4ea08bdaeee5d and following commits +** contributed by Manfred Moser, http://www.simpligility.com +* forcing maven version and setting a few more plugin versions as well as updating some +** see https://github.com/mosabua/ksoap2-android/commit/e56e72e1b3162e35aa02c3b14ad1bf4d952e64b6 +** contributed by Manfred Moser, http://www.simpligility.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.6.1 Release, 2012-01-16 + +* issue 94 fix, no NPE with non string properties +** contributed by Dawid Drozd https://github.com/gelldur +* added support to manage the order of SoapObject? properties (PropertyInfos? and SoapObjects?) +** see https://github.com/mosabua/ksoap2-android/pull/10 +** contributed by Andrew Oppenlander http://themented.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.6.0 Release, 2011-11-17 + +* issue 84 fix, correct Content-Type in SOAP 1.2 +** contributed by elias.nystrom and Manfred Moser +* issue 87 fix, setting charset to utf-8 +** contributed by tauit.dnmd and Manfred Moser +* removed deprecated Android specific classes, since they did not actually have any actual behaviour anyway, use HttpTransportSE instead +** see https://github.com/mosabua/ksoap2-android/commit/352841817a8898d4c794e2b8d3d6bdfb81da96be +** contributed by Manfred Moser, http://www.simpligility.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.5.8 Release, 2011-09-26 + +* issue 75 fix, removing array type if implicitTypes is on +** see https://github.com/mosabua/ksoap2-android/pull/8 +** contributed by John Lindeman +* issue 77 fix, allowing empty body out +** contributed by Finn Larsen and Manfred Moser +* implemented correct SoapFault? for SOAP 1.2 +** contributed by Petter Uvesten, http://www.everichon.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.5.7 Release, 2011-07-06 + +* issue 10 fix +** contributed by Manfred Moser, http://www.simpligility.com +* issue 60 and issue 52 fixed +** contributed by Manfred Moser, http://www.simpligility.com +* correct removal of SOAPAction for 1.2, ** fixes issue 67 +** contributed by Petter Uvesten, http://www.everichon.com +* correct header for 1.2, ** fixes issue 68 +** contributed by Petter Uvesten, http://www.everichon.com + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.5.6 Release, 2011-06-22 + +* convenience methods for getting string representation of attributes and properties off SoapObjects? +** contributed by Manfred Moser +* convenience methods for adding attributes and properties to SoapObject? only if not null +** contributed by Manfred Moser + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.5.5 Release, 2011-06-06 + +* license and contributor details updated +* SoapObject#addSoapObject? +** contributed by Andrew Oppenlander +* refactored safeGetX to getXSafely in SoapObject? +** contributed by Manfred Moser + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.5.4 Release, 2011-02-04 + +* fixed bug in URI properties acquisition +* added feature to manage cookies across request response communication +* javadoc updates +* exposed connection in transport for access +* fixed property count returned in getResponse https://github.com/mosabua/ksoap2-android/commit/1184019043cc63e7439f577cf740cc3cdb88e923 + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.5.3 Release, 2011-02-04 + +* see 2.5.4 release, the release process failed for this release number due to technical difficulties + +=== 2.5.2 Release, 2010-11-01 + +* added https transport +** fixing issue 6 http://code.google.com/p/ksoap2-android/issues/detail?id=6 +* deprecated android https transport classes since they are null change implementations of the SE ones and conflict with Android SDK class names too ( a future release will remove these classes) +* applied vector node patch fixing issue 29 http://code.google.com/p/ksoap2-android/issues/detail?id=29 +* updated copyright file with more details from contributors + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.5.1 Release, 2010-10-12 + +After merging a bunch patches and figuring out how to do a release I have created a 2.5.1 release and deployed it to the Maven repo on google code. Included fixes + +* attribute reading working issues http://code.google.com/p/ksoap2-android/issues/detail?id=17 and http://code.google.com/p/ksoap2-android/issues/detail?id=4 +* patch for empty soap fault detail +* a bunch of convenience methods for working with soapobjects + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2.3 Release, 2009-08-16 + +Version 2.3 of the ksoap2-android project was released on Sunday, 2009-08-16. This release contains fixes for the following issues: + +* Issue 2: Duplicated AndroidHttpTransport.class and AndroidServiceConnection.java files in the release JAR. +* Issue 3: AndroidServiceConnection is using wrong httpclient library version + +Other Announcements + +2010-10-12 Wiki overhaul +I did a major overhaul of the wiki and the content on it as well as adding more content. + +Release performed by Manfred Moser http://www.simpligility.com + +=== 2010-10-08 Project Owner Change + +The project has been dormant for too long and as of today has been taken over by Manfred Moser http://www.simpligility.com. Thanks to Karl Davies for past project creation and maintenance + +In the near term the following steps are planned: + +* applying some of my own patches +* applying some patches I received from various other community members +* updating the wiki to reflect the new state +* various other tasks that might come up +* create a new release + +We will create issues for all these tasks shortly and track progress with the issue tracker. + +A new mailing list has been created so please feel free to join the list and post any ideas or questions there. + +Manfred + +==== 2009-08-16, Development Status + +My apologies for the long hiatus in updates to this project. I was actually quite surprised to discover today that others were making use of it. I just pushed out a new release (2.3) to resolve the issues folks were having making use of it. + +If you'd like to help contribute to this project, please let me know. I'll try to put up a page with build instructions sometime in the near future. diff --git a/src/site/asciidoc/contributing.adoc b/src/site/asciidoc/contributing.adoc new file mode 100644 index 00000000..4be247f6 --- /dev/null +++ b/src/site/asciidoc/contributing.adoc @@ -0,0 +1,65 @@ +== Contributing + +=== Why Contribute + +The project is mostly in maintenance mode and has only minor active development. +We will however take new contributions, test them a bit and cut new releases so +that everyone can get the benefits of your fixes ;-) + +If you want to get new features or bugs fixed feel free to report them in the +issue tracker, but be aware that it would be best if you fix them yourself in +a clone of the github repository and we will gladly pull the enhancement into +the project. + +When creating a contribution please ensure that you have based your patch off +the latest version in the github project so that the merge will be easy. You +also need to ensure that the project source code at least compiles and can be +built with Maven. + +=== More Details + +We welcome any contribution in the forms of feedback on social media, helping +out on stackoverflow, whatever you can do helps. This page however focuses on +how to contribute either documentation or source code. All of it is contained in +the same git repository. + +=== Prerequisites + +You will have to either know git already or learn it. You will love it! Minor +documentation or spelling fixes can be performed directly in the github user +interface. Anything beyond that needs a local repository and more. + +=== Flow of Contributions + +Once to know how to use git you + +* fork the repository to your own github account +* create a branch for your specific work (separate issues or changes should be separate branches) +* verify it all builds and looks right (see the 'Developing' documentation for more on that) +* send a pull request +* the core committers will review the pull request +* any suggested changes need to be done on the same branch and pushed to your repository, this will update the pull request +* ideally two core committers agree and will pull in the change +* the changelog then gets updated and you are done +* delete your branch and pull in from upstream master +* rinse and repeat ... + +=== Documentation Contributions + +All documentation is written in asciidoc and should be located in +src/site/asciidoc+. +Navigation and other layout and design resources can be found in +src/site+ and +specifically +src/site/site.xml+. The documentation is published with each release +and is available on GitHub. You can edit documentation in the github interface +or in your local clone. Check out the documentation on +link:developing.html[developing] for further tips and tricks. + + +=== Code Contributions + +A contribution can be anything useful to the project. It might be fixing an +issue or enhancing the plugin somehow. Even a javadoc spelling fix is not too +small to submit! The only thing you need to check is that you can build the +plugin, because we enforce things like code style and so on automatically. +However if you create a pull request, this is done automatically as part of +our continuous integration setup. Check out the documentation on +link:developing.html[developing] for further tips and tricks. diff --git a/src/site/asciidoc/contributors.adoc b/src/site/asciidoc/contributors.adoc new file mode 100644 index 00000000..9865ea43 --- /dev/null +++ b/src/site/asciidoc/contributors.adoc @@ -0,0 +1,35 @@ +== Contributors + +The ksoap2-android has received contributions from individuals and companies. The source +code repository includes a https://github.com/simpligility/ksoap2-android/graphs/contributors[list of contributor]. + +These contributions are managed by Manfred Moser from simpligility. + +The following companies provide support for core contributors: + +* http://www.simpligility.com/[simpligility] - core maintenance since Oct 2010 + +Other contributions have been sponsored by + +* easywsdl + +Please let us know if we have omitted you! + +=== History + +Long ago there was the ksoap and then the ksoap2 projects. After a successful +phase SOAP and with it the library pretty much died. (at least there were no +release since 2006 or so) + +Android then revived that since a lightweight framework to talk to legacy SOAP +services was needed. + +A patch set for Android emerged on the "Android Developers" Google group +authored by Jorge Jimenez. + +Karl Michael Davis then took this patchset, set up a proper Apache Maven build +as well as this project and did a few releases. + +Since the project was largely unmaintained in 2009/2010 Manfred Moser from simpligility technologies inc. took over the project, updated the wiki, created +a mailinglist, applied and created further patches and released 2.5.1 and has +been cutting numerous releases with a number of enhancements since then. \ No newline at end of file diff --git a/src/site/asciidoc/developing.adoc b/src/site/asciidoc/developing.adoc new file mode 100644 index 00000000..4b9bdae9 --- /dev/null +++ b/src/site/asciidoc/developing.adoc @@ -0,0 +1,51 @@ +== Developing + +If you want to help on the actual codebase, here is what you need + +=== Pre-requisites + +* Apache Maven installed - (3.1.1 or higher as enforced during the build) +* Alternatively use the mvnw wrapper scripts +* Optionally for better testing and debugging support any Java IDE +* Optionally git or svn to get the code from github, unless you download the source as zip + +=== Getting the code + +You can just get the code from github as usual from the site https://github.com/simpligility/ksoap2-android/ + +---- +git clone git@github.com:simpligility/ksoap2-android.git +---- + + +=== Building + +The usual Maven invocations apply. A full build is done with + +---- +mvn clean install +---- + +or using the Maven wrapper + +---- +mvnw clean install +---- + +The documentation website can be built with + +---- +mvn clean site -N +---- + +with the resulting HTML found in +target/site/+. + +=== Coding Style + +The Maven build enforces a code style with the Maven Checkstyle Plugin to +make the code more readable and consistent as well as to avoid problems with +merges we had in the past when it comes to tabs vs. spaces and others. + +The checkstyle rules are all defined +https://github.com/simpligility/ksoap2-android/blob/master/build-tools/src/main/resources/simpligility/checkstyle.xml + diff --git a/src/site/asciidoc/getting-started.adoc b/src/site/asciidoc/getting-started.adoc new file mode 100644 index 00000000..f336f6af --- /dev/null +++ b/src/site/asciidoc/getting-started.adoc @@ -0,0 +1,84 @@ +== Getting Started + +The first step for using the libraries provided from ksoap2-android is +to add the desired JAR libraries to the classpath. + +All files are provided in Maven repositories hosted by Sonatype: + +Releases:: https://oss.sonatype.org/content/repositories/ksoap2-android-releases/[https://oss.sonatype.org/content/repositories/ksoap2-android-releases/] +Snapshots (Development Versions):: https://oss.sonatype.org/content/repositories/ksoap2-android-snapshots/[https://oss.sonatype.org/content/repositories/ksoap2-android-snapshots/] + +=== Apache Maven + +To make use of this library in a Maven project, add the following to your project's POM: + +---- + + ... + + + com.google.code.ksoap2-android + ksoap2-android + 3.6.4 + + + ... + +---- + +and configure a proxy repository in your repository manager using the URL of the +release repository above. + +If you are not using a repository manager like http:/www.sonatype.org/nexus[Sonatype Nexus], you should start doing so now. + +As a stop gap solution you could add the repository to a profile in your +settings.xml or pom.xml: + +---- + + + ossrh + https://oss.sonatype.org/content/repositories/ksoap2-android-releases/ + + +---- + +Further libraries as part of the project are also published as part of the build +and can be declared as dependencies as well, if needed. E.g. + +---- + + com.google.code.ksoap2-android + ksoap2-extra-ntlm + 3.6.4 + +---- + +And a number of others. Check out the project source for more. + +=== Gradle + +The same coordinates for the JAR and the release repository URL as used for +Apache Maven can be used. + +=== Apache Ant-based build and Eclipse/ADT + +To make use of this library in a non-Maven project, follow the instructions in +the http://developer.android.com/guide/index.html[Android Developer's Guide] on +how to http://developer.android.com/guide/appendix/faq/commontasks.html#addexternallibrary[Add an External Library] to your project. + +You will need to add a ksoap2-android and all required transitive dependencies +to the build path. Luckily the Maven build of the project produces a nice bundle +of all these jars in one big file. + +The different version of these files are available at https://oss.sonatype.org/content/repositories/ksoap2-android-releases/com/google/code/ksoap2-android/ksoap2-android-assembly/. + +The latest release artifact of the bundle is available at + +https://oss.sonatype.org/content/repositories/ksoap2-android-releases/com/google/code/ksoap2-android/ksoap2-android-assembly/3.6.4/ksoap2-android-assembly-3.6.4-jar-with-dependencies.jar + +=== Next Steps + +In terms of how to write your code please look at the +link:howto.html[some of the many tutorials from the community] and check out +our link:tips.html[collection of tips and tricks]. \ No newline at end of file diff --git a/src/site/asciidoc/howto.adoc b/src/site/asciidoc/howto.adoc new file mode 100644 index 00000000..22494b6e --- /dev/null +++ b/src/site/asciidoc/howto.adoc @@ -0,0 +1,55 @@ +== How to Use ksoap2-android + +The documentation for ksoap2-android is a bit sparse on the site here. We +welcome contributions. Fortunately there is a lot of other documentation +available. + +== Mailing list == + +Join the mailing list http://groups.google.com/group/ksoap2-android as it is the +main forum for discussion and help. Please send any questions there. + +== Stackoverflow == + +You can also create a question on Stackoverflow and use the ksoap2 and android +tag or the android-ksoap2 tag and we might find your question there.. + +* http://stackoverflow.com/questions/tagged/ksoap2 +* http://stackoverflow.com/questions/tagged/android-ksoap2 + +== Source and Javadoc == + +A very good source of documentation are the javadoc as well as the source both +of which you can find in the project Maven repository. The source in the github +repository also contains numerous test that show how to do various things like +creating requests and parsing results and so on. + +If you use Maven javadoc and sources will all be hooked up in your IDE +automatically and you can browse the source and documentation right during +development. This should also work with Gradle. + +To do the same with Ant or plain Android Development Toolkit (Eclipse plugin) +based environment you will have to manually download the source and javadoc jar +files. + +=== Useful External Resources and Tutorials + +* http://www.helloandroid.com/tutorials/using-ksoap2-android-and-parsing-output-data - Parsing tutorial on helloandroid +* http://www.simpligility.com/2010/05/attribute-support-for-ksoap2-on-android/- First announcement of patch for working attribute support published by current project maintainer on his company website +* KSoap Android Web Service Tutorial With Sample Code - http://seesharpgears.blogspot.com/2010/10/ksoap-android-web-service-tutorial-with.html +* Web Service That Returns An Array of Objects With KSOAP - http://seesharpgears.blogspot.com/2010/10/web-service-that-returns-array-of.html +* Returning Array of Primitive Types with KSOAP http://seesharpgears.blogspot.com/2010/11/returning-array-of-primitive-types-with.html +* Implementing KSOAP Marshal Interface http://seesharpgears.blogspot.com/2010/11/implementing-ksoap-marshal-interface.html] +* Introduction to using KSoap2 Android http://naveenbalani.com/index.php/2011/01/invoke-webservices-from-android/ +* http://roderickbarnes.com/blog/droid-chronicles-web-services-part-1 +* http://roderickbarnes.com/blog/the-droid-chronicles-web-services-part-2-sophisticated-android-clients +* http://roderickbarnes.com/blog/the-droid-chronicles-web-services-passing-parameters +* http://roderickbarnes.com/blog/the-droid-chronicles-web-services-preventing-problems-with-passing-parameters +* http://roderickbarnes.com/blog/droid-chronicles-web-services-handling-complex-parameters +* http://roderickbarnes.com/blog/the-droid-chronicles-an-android-webrowset-implementation-bifrowset +* Useful tips for dealing with SSL/HTTPShttp://donmacvittie.ulitzer.com/node/2596103] +* http://ksoap2.sourceforge.net/ - KSoap2 upstream project site, no longer maintained + +=== Other Tips & Tricks + +... can be found on link:tips.html[our dedicated page]. \ No newline at end of file diff --git a/src/site/asciidoc/index.adoc b/src/site/asciidoc/index.adoc new file mode 100644 index 00000000..8dce0e12 --- /dev/null +++ b/src/site/asciidoc/index.adoc @@ -0,0 +1,42 @@ +== ksoap2-android - lightweight, efficient SOAP on Android + +=== Introduction + +The ksoap2-android project provides a lightweight and efficient SOAP client +library for the Android platform. + +It is a fork of the http://ksoap2.sourceforge.net/[kSOAP2 library] that is +tested mostly on the Android platform, but should also work on other platforms +using Java libraries. + +Up to version 3.4.0, it is still using Java 1.3 so should work fine on JavaME, +Blackberry and so on. Beyond that Java 1.5 is set as the language level. + +ksoap2-android has been consistently enhanced and expanded with more features. +It is actively maintained and we welcome bug fixes and contributions. Releases +are done semi-regularly with community contributions in the form of enhancements +and more. + +=== Support + +For more information check out the pages and linked content of this site and +join http://groups.google.com/group/ksoap2-android[our mailing list]. + +And for the impatient the jars are available in a Maven repository or for +download from there as a bundle. More at link:getting-started[Getting Started]. + +=== License + +ksoap2-android is licensed under MIT and can therefore be included in your +commercial application. If you intend to do so please read the details on the +link:license-information.html[Licensing page]. + +=== Users + +You are interested to see a list of projects using ksoap2-android -> link:users.html[Check it out] + +=== Sponsors + +Project maintenance sponsored by Manfred Moser of http://www.simpligility.com[simpligility]. + +Maven repository hosting is sponsored by http://www.sonatype.com[Sonatype]. \ No newline at end of file diff --git a/src/site/asciidoc/license-information.adoc b/src/site/asciidoc/license-information.adoc new file mode 100644 index 00000000..9760ca15 --- /dev/null +++ b/src/site/asciidoc/license-information.adoc @@ -0,0 +1,27 @@ +== License Information + +Ksoap2-android itself is licensed under an MIT license. It depends on other +libraries licensed under different licenses. + +Some source files include different licensing information in the header. In each +case, they appear to be Apache and BSD licenses. If this is a concern, use care +to examine the licenses and ensure they are compatible with your project. + +=== Details + +* Ksoap2-android, MIT, https://github.com/mosabua/ksoap2-android +* kxml2, permissive license, https://github.com/mosabua/kxml2 +* kobjects, permissive license, https://github.com/mosabua/kobjects +* xmlpull, public domain, https://github.com/mosabua/xmlpull + +=== Commercial Usage + +It is the understanding of the current maintainers and committers that the +licenses allow inclusion in proprietary application without a viral effect on +the code of the application. We have not heard anything to the contrary from +anyone, however we are not lawyers. + +=== Credit + +We would appreciate a credit in the application and a notification that you +are using the library. It would also be great if you allow us to link to your application as a show case example. \ No newline at end of file diff --git a/src/site/asciidoc/releasing.adoc b/src/site/asciidoc/releasing.adoc new file mode 100644 index 00000000..feb4d616 --- /dev/null +++ b/src/site/asciidoc/releasing.adoc @@ -0,0 +1,107 @@ +== Releasing + +This should be of no interest to developers using ksoap2-android for Android +applications. This is for those developers of ksoap2-android who perform releases. + +=== Getting Ready + +Ensure that the upcoming release version is used in +`org.ksoap2.transport.Transport.USER_AGENT`. + +You have to be able to do full build as well as be able to build the site: + +---- +mvn clean install +mvn site -N +---- + +Beyond that you need all the setup to deploy to the OSSRH. Follow the +http://central.sonatype.org[setup instructions]. In addition you need to have +permissions to deploy to the repository. Contact the project owners, if required. + +Mainly you need to have your OSSRH credentials in +settings.xml+. + +---- + + ossrh + yourname + yourpassword + +---- + +For site deployment you need to add your github credentials for the site +deployment to github pages to work: + +---- + + github + yourname + yourpassword + +---- + +=== Deploy a SNAPSHOT version + +If you want to make a binary version available for someone to test, +before making a proper release, deploy a SNAPSHOT version. This will make it available in the +snapshots repo at https://oss.sonatype.org/content/repositories/ksoap2-android-snapshots + +To perform the SNAPSHOT release: + +---- +mvn clean deploy -P release +---- + + +=== Perform a RELEASE + +This is the real deal. + +- all tests pass +- site build passes +- changelog is up to date including the release date! + +Once you are happy with the state of everything - Do it! + +To perform the release: + +---- +mvn release:prepare release:perform +---- + +If something goes wrong during the perform phase you can deploy from the target/checkout folder +or checkout a branch of the tag. + +---- +mvn deploy -P release +---- + +With the right setup this will + +* create a tag and push it to github +* prepare and deploy everything for the plugin release (jar, sources, javadoc..) to OSSRH + +Check https://oss.sonatype.org/content/repositories/ksoap2-android-releases/ + +Announce on the mailing list, G+, Twitter and maybe ADT and other lists as desired. + +To obtain a correct permanent link to the announcement email, go to the mailing list group, +open the announcement post and click the little chain/link icon to the right. + +Once you are done with it all, celebrate as desired ;-) + +=== After the release + +* update changelog for next version +* add release notes mailing list permanent link changelog +* deploy the site from the release branch/tag in target/checkout + +=== Deploy the site + +Deploying the site to github pages can be done any time with: + +---- +mvn clean site-deploy -N +---- + +For a release check out the tag in git or right after running the release run the command in `target/checkout`. \ No newline at end of file diff --git a/src/site/asciidoc/report-issue.adoc b/src/site/asciidoc/report-issue.adoc new file mode 100644 index 00000000..de4c1024 --- /dev/null +++ b/src/site/asciidoc/report-issue.adoc @@ -0,0 +1,16 @@ += Report An Issue + +Reporting issues is important. Ideally this is what you do to file an issue and +get it fixed. The less of these steps you follow the smaller the chances are +that your issue gets fixed.. + +* Verify with the latest release +* Provide detailed description of the problem +* Create a sample project that show-cases the issue +* Or provide some other means of reproducing the issue +* Answer any questions from the project team + +Now that you know what you should do, https://github.com/simpligility/ksoap2-android/issues[go ahead an file an issue]. + +The next steps would be to fix the issue by following our instructions about link:contributing.html[contributing.] + diff --git a/src/site/asciidoc/tips.adoc b/src/site/asciidoc/tips.adoc new file mode 100644 index 00000000..19549bea --- /dev/null +++ b/src/site/asciidoc/tips.adoc @@ -0,0 +1,393 @@ +== Tips and Tricks + +=== Sending/receiving array of complex types or primitives + +You have to extend Vector an implement KvmSerializable. +see also http://www.blackberry-forum.de/cgi-bin/YaBB.pl?num=1260616413 + +We want to generate this XML in the Request +---- + + string + string + +string +string +---- + +As you see, we want to generate an array with the Propertyname "documentIds" +which contains strings with the propertyname "string", and to other simple +string properties called "pluginType" and "xmlConfiguration". + +For this you have to generate a class like this: + +---- +import java.util.Hashtable; +import java.util.Vector; +import org.ksoap2.serialization.KvmSerializable; +import org.ksoap2.serialization.PropertyInfo; + +public class DocumentIDs extends Vector implements KvmSerializable { + + private static final long serialVersionUID = -1166006770093411055L; + + @Override + public Object getProperty(int arg0) { + return this.get(arg0); + } + + @Override + public int getPropertyCount() { + return 1; + } + + @Override + public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) { + arg2.name = "string"; + arg2.type = PropertyInfo.STRING_CLASS; + } + + @Override + public void setProperty(int arg0, Object arg1) { + this.add(arg1.toString()); + } + +} +---- + +To build the request you have to do this: + +Make a new Vector-Object from this class: + +---- +DocumentIDs documentIdVector = new DocumentIDs(); +---- + +then you can add elements: + +---- +documentIdVector.add("any String"); +---- + +then you create a PropertyInfo with it: + +---- +documentIdsPropertyInfo = new PropertyInfo(); +documentIdsPropertyInfo.setName("documentIds"); +documentIdsPropertyInfo.setValue(documentIdVector); +documentIdsPropertyInfo.setType(documentIdVector.getClass()); +---- + +then you add all the properties to the request: +---- +Request = new SoapObject(NAMESPACE, METHOD_NAME); +Request.addProperty(documentIdsPropertyInfo); +Request.addProperty("pluginType", "another string"); +Request.addProperty("xmlConfiguration", "next string"); + +soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); +soapEnvelope.setOutputSoapObject(Request); +soapEnvelope.addMapping(NAMESPACE, "documentIds", new DocumentIDs().getClass()); +---- + +When receiving a Response you simply cast the soapEnvelope.bodyIn to the class +the response contains. and then access the Vector entries with an index and the +values of a complex-type entry with getter-methods. + +in the above case this whould be + +---- +DocumentIDs documentIdResultVector = (DocumentIDs)soapEnvelope.bodyIn; +String resultString = documentIdResultVector.get(0); +---- + +=== How to see raw xml request and response e.g. for debugging? + +Turn debugging on for your httpTransport like so + +---- +httpTransport.debug = true; +---- + +and then set a breakpoint at + +---- +httpTransport.call(soapaction, envelope); +---- + +inspect the values of + +---- +httpTransport.requestDump +httpTransport.responseDump +---- + +=== Is there code generation off the WSDL somehow? + +The leading WSDL client code generator EasyWsdl[https://www.easywsdl.com/] +produces code that facilitates ksoap2-android. + +There is the also a less mature project [http://code.google.com/p/wsdl2ksoap/] +that uses KSoap2-Android as well as a patch that enables something along these +lines in upstream KSoap2 (details on http://code.google.com/p/ksoap2-android/issues/detail?id=34 + however that is all I know about it.. + +=== Marshalling Arrays + +Writing a three dimensional array (as an example) can be done with a Marshaller +implemented e.g. like that, reading still needs to be done + +---- +import org.ksoap2.serialization.Marshal; +import org.ksoap2.serialization.PropertyInfo; +import org.ksoap2.serialization.SoapSerializationEnvelope; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; + +public class MarshallArray implements Marshal { + //this method doesn't work yet + public Object readInstance(XmlPullParser parser, String namespace, String name, PropertyInfo expected) + throws IOException, XmlPullParserException { + return parser.nextText(); + } + + public void register(SoapSerializationEnvelope cm) { + cm.addMapping(cm.xsd, "String[][][]", String[][][].class, this); + } + + public void writeInstance(XmlSerializer writer, Object obj) throws IOException { + String[][][] myArray = (String[][][]) obj; + for (int i = 0; i < myArray.length; i++) { + writer.startTag("", "ArrayOfArrayOfString"); + for (int j = 0; j < myArray[i].length; j++) { + writer.startTag("", "ArrayOfString"); + for (int k = 0; k < myArray[i][j].length; k++) { + writer.startTag("", "string"); + writer.text(myArray[i][j][k]); + writer.endTag("", "string"); + } + writer.endTag("", "ArrayOfString"); + } + writer.endTag("", "ArrayOfArrayOfString"); + } + } +} + +---- + +=== Manual Parsing of an Array of SoapObjects into an POJO array + +You can create an array of pojos by just parsing through a SoapObjects +properties, which are each SoapObjects themselves. Your response returned from +the webservice will be a SoapObject (unless it is very simple - SoapPrimitive +then, or it failed.. SoapException then) and you can parse it manually with the +various methods like getProperty, getAttribute and so on. See the javadoc for +SoapObject for more. + +---- +ArrayList pojos = null; +int totalCount = soapobject.getPropertyCount(); +if (detailsTotal > 0 ) { + pojos = new ArrayList(); + for (int detailCount = 0; detailCount < totalCount; detailCount++) { + SoapObject pojoSoap = (SoapObject) soapobject.getProperty(detailCount); + Pojo Pojo = new Pojo(); + Pojo.idNumber = pojoSoap.getProperty("idNumber").toString(); + Pojo.quantity = pojoSoap.getProperty("quantity").toString(); + + pojos.add(Pojo); + } +} +---- + +=== How to build up a Element array e.g. for the security header of the request + +See [http://stackoverflow.com/questions/4194920/blackberry-ksoap2-soap-header] + +=== Adding an array of complex objects to the request + +To get this xml: +---- + + + Jonh + 12 + + + Marie + 27 + + +---- + +You would do this: +---- +SoapObject users = new SoapObject(NAMESPACE, "users"); +SoapObject john = new SoapObject(NAMESPACE, "user"); +john.addProperty("name", "john"); +john.addProperty("age", 12); +SoapObject marie = new SoapObject(NAMESPACE, "user"); +john.addProperty("name", "marie"); +john.addProperty("age", 27); +users.addSoapObject(john); +users.addSoapObject(marie); +---- + +In a similar manner if you have an array of objects or primitives you can build +a loop iterating through and adding as above. The approach above works as of +2.5.5. Prior you have to create a SoapObject and add it as a property. + +Or look above to "sending/receiving array of complex types or primitives" + +You can also add any required attributes to each SoapObject as necessary. + +=== How to set the SSLSocketFactory on a https connection in order to allow self-signed certificates read from a KeyStore + +---- +public class ConnectionWithSelfSignedCertificate { + + private KeyStore keyStore; + + public ConnectionWithSelfSignedCertificate(KeyStore keyStore) { + this.keyStore = keyStore; + } + + public void dummy(String host, int port, String file, int timeout) throws Exception { + SoapObject client = new SoapObject("", "dummy"); + SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + envelope.bodyOut = client; + HttpsTransportSE transport = new HttpsTransportSE(host, port, file, timeout); + ((HttpsServiceConnectionSE) transport.getConnection()).setSSLSocketFactory(getSSLSocketFactory()); + transport.call("", envelope); + } + + private SSLSocketFactory getSSLSocketFactory() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(keyStore); + SSLContext context = SSLContext.getInstance("SSL"); + context.init(null, tmf.getTrustManagers(), null); + return context.getSocketFactory(); + } +} + +---- + +=== Sending a byte array + +To send a byte array (e.g an image) you need to enable MarshalBase64 by adding +it as a mapping to the envelope and then add the byte array as a base64 encoded +array. + +---- +String path = Environment.getExternalStorageDirectory().getAbsolutePath(); + String FILE = "/PdfCheck1.pdf"; + String pathCompleto = path+FILE; + Log.i("","Path completo : "+ pathCompleto); + byte[] filefirma = convertDocToByteArray(pathCompleto); + Intervento.addProperty("FileFirma",filefirma); + +SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); + +new MarshalDouble().register(envelope); +new MarshalBase64().register(envelope); //serialization +envelope.encodingStyle = SoapEnvelope.ENC; + +envelope.bodyOut = request; +envelope.dotNet = true; +envelope.setOutputSoapObject(request); +envelope.setAddAdornments(false); +envelope.implicitTypes= true; +// Log.i("Envelope","settata"); + +HttpTransportSE androidHttpTransport = new HttpTransportSE(URL); +androidHttpTransport.debug = true; +Log.i("","Prima di androidHttpTransport.call "); +androidHttpTransport.call(SOAP_ACTION, envelope); +Log.i("","" + androidHttpTransport.requestDump); +Log.i("","" + androidHttpTransport.responseDump); +Log.i("call","call"); + +SoapPrimitive resultsRequestSOAP = (SoapPrimitive) envelope.getResponse(); +Log.i("SoapPrimitive","Result" + resultsRequestSOAP); +Log.i("GetAttribute","Count" + resultsRequestSOAP.getAttributeCount()); + +b = Boolean.parseBoolean(resultsRequestSOAP.toString()); +Log.i("","risultato boolean Straordinario "+b); + +public static byte[] convertDocToByteArray(String sourcePath) throws IOException { + File f = new File(sourcePath); + long l = f.length(); + byte [] buf = new byte[(int) l]; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + InputStream fis = new FileInputStream(sourcePath); + + for (int readNum; (readNum = fis.read(buf)) != -1;) { + bos.write(buf, 0, readNum); + Log.i("","read num bytes: "+readNum); + } + } catch (IOException e) { + System.out.println("IO Ex"+e); + } + byte[] bytes = bos.toByteArray(); + +// for(int i = 0;i + + ${project.name} + + + + + + org.apache.maven.skins + maven-fluido-skin + 1.7 + + + + true + true + + + + + mosabua/ksoap2-android + right + orange + + » + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file