Merge pull request #18 from henrykuijpers/feature/SLING-9750-fix-obtaining-of-id-when-not-int-value

SLING-9750 Fix read string as integer issue
diff --git a/bnd.bnd b/bnd.bnd
new file mode 100644
index 0000000..f1cd5bd
--- /dev/null
+++ b/bnd.bnd
@@ -0,0 +1,3 @@
+-removeheaders:\
+  Include-Resource,\
+  Private-Package
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index adea101..b87a9af 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,14 +22,13 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.sling</groupId>
-        <artifactId>sling</artifactId>
-        <version>34</version>
+        <artifactId>sling-bundle-parent</artifactId>
+        <version>39</version>
         <relativePath />
     </parent>
 
     <artifactId>org.apache.sling.testing.clients</artifactId>
-    <version>2.0.3-SNAPSHOT</version>
-    <packaging>bundle</packaging>
+    <version>2.0.5-SNAPSHOT</version>
 
     <name>Apache Sling Testing Clients</name>
     <description>
@@ -40,33 +39,17 @@
         <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-clients.git</developerConnection>
         <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-testing-clients.git</url>
         <tag>HEAD</tag>
-  </scm>
+    </scm>
     
     <build>
         <plugins>
-             <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <configuration>
-                    <instructions>
-                        <Export-Package>
-                            org.apache.sling.testing.clients,
-                            org.apache.sling.testing.clients.html,
-                            org.apache.sling.testing.clients.instance,
-                            org.apache.sling.testing.clients.interceptors,
-                            org.apache.sling.testing.clients.osgi,
-                            org.apache.sling.testing.clients.util,
-                            org.apache.sling.testing.clients.util.config,
-                            org.apache.sling.testing.clients.util.poller,
-                            org.apache.sling.testing.clients.*
-                        </Export-Package>
-                        <Import-Package>
-                            org.apache.commons.exec.*; resolution:=optional,
-                            *
-                        </Import-Package>
-                    </instructions>
-                </configuration>
+            <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-baseline-maven-plugin</artifactId>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
diff --git a/src/main/java/org/apache/sling/testing/clients/SlingClient.java b/src/main/java/org/apache/sling/testing/clients/SlingClient.java
index 58c4ef3..75814ca 100644
--- a/src/main/java/org/apache/sling/testing/clients/SlingClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/SlingClient.java
@@ -16,6 +16,16 @@
  */
 package org.apache.sling.testing.clients;
 
+import static org.apache.http.HttpStatus.SC_CREATED;
+import static org.apache.http.HttpStatus.SC_OK;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpRequestInterceptor;
@@ -25,6 +35,7 @@
 import org.apache.http.client.CookieStore;
 import org.apache.http.client.CredentialsProvider;
 import org.apache.http.client.RedirectStrategy;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -32,20 +43,15 @@
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.sling.testing.clients.interceptors.DelayRequestInterceptor;
 import org.apache.sling.testing.clients.interceptors.TestDescriptionInterceptor;
-import org.apache.sling.testing.clients.util.*;
+import org.apache.sling.testing.clients.util.FormEntityBuilder;
+import org.apache.sling.testing.clients.util.HttpUtils;
+import org.apache.sling.testing.clients.util.JsonUtils;
+import org.apache.sling.testing.clients.util.ServerErrorRetryStrategy;
 import org.apache.sling.testing.clients.util.poller.AbstractPoller;
 import org.apache.sling.testing.clients.util.poller.Polling;
+import org.apache.sling.testing.timeouts.TimeoutsProvider;
 import org.codehaus.jackson.JsonNode;
 
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-import static org.apache.http.HttpStatus.SC_CREATED;
-import static org.apache.http.HttpStatus.SC_OK;
-
 /**
  * <p>The Base class for all Integration Test Clients. It provides generic methods to send HTTP requests to a server. </p>
  *
@@ -56,6 +62,7 @@
 public class SlingClient extends AbstractSlingClient {
 
     public static final String DEFAULT_NODE_TYPE = "sling:OrderedFolder";
+    public static final String CLIENT_CONNECTION_TIMEOUT_PROP = "sling.client.connection.timeout.seconds";
 
     /**
      * Constructor used by Builders and adaptTo(). <b>Should never be called directly from the code.</b>
@@ -692,6 +699,17 @@
             // HTTP request strategy
             httpClientBuilder.setServiceUnavailableRetryStrategy(new ServerErrorRetryStrategy());
 
+            // connection timeouts
+            int timeoutSeconds = TimeoutsProvider.getInstance().getTimeout(CLIENT_CONNECTION_TIMEOUT_PROP, -1);
+            if (timeoutSeconds > 0) {
+                int timeoutMs = (int)TimeUnit.SECONDS.toMillis(timeoutSeconds);
+                RequestConfig config = RequestConfig.custom()
+                        .setConnectTimeout(timeoutMs)
+                        .setConnectionRequestTimeout(timeoutMs)
+                        .setSocketTimeout(timeoutMs).build();
+                this.httpClientBuilder.setDefaultRequestConfig(config);
+            }
+
             return this;
         }
 
diff --git a/src/main/java/org/apache/sling/testing/clients/package-info.java b/src/main/java/org/apache/sling/testing/clients/package-info.java
index b8c2d58..94da83e 100644
--- a/src/main/java/org/apache/sling/testing/clients/package-info.java
+++ b/src/main/java/org/apache/sling/testing/clients/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("2.1.0")
+@Version("2.2.0")
 package org.apache.sling.testing.clients;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/testing/clients/query/servlet/QueryServlet.java b/src/main/java/org/apache/sling/testing/clients/query/servlet/QueryServlet.java
index 54cdc1f..7b01e8b 100644
--- a/src/main/java/org/apache/sling/testing/clients/query/servlet/QueryServlet.java
+++ b/src/main/java/org/apache/sling/testing/clients/query/servlet/QueryServlet.java
@@ -46,7 +46,7 @@
     private static final long serialVersionUID = 1L;
 
     public static final String SERVLET_PATH = "/system/testing/query";
-    public static final String SERVLET_NAME = "Sling Testing Clients Query Servlet";
+    public static final String SERVLET_NAME = "sling.testing.clients.query.servlet";
 
     @Override
     protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
diff --git a/src/main/java/org/apache/sling/testing/clients/query/servlet/package-info.java b/src/main/java/org/apache/sling/testing/clients/query/servlet/package-info.java
index 0263e62..d5118d4 100644
--- a/src/main/java/org/apache/sling/testing/clients/query/servlet/package-info.java
+++ b/src/main/java/org/apache/sling/testing/clients/query/servlet/package-info.java
@@ -19,7 +19,7 @@
 /**
  * Query tools leveraging javax.jcr.query
  */
-@Version("1.2.2")
+@Version("1.2.3")
 package org.apache.sling.testing.clients.query.servlet;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/test/java/org/apache/sling/testing/clients/SlingClientConnectionTimeoutTest.java b/src/test/java/org/apache/sling/testing/clients/SlingClientConnectionTimeoutTest.java
new file mode 100644
index 0000000..117deae
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/clients/SlingClientConnectionTimeoutTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+package org.apache.sling.testing.clients;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+/**
+ * SLING-9757 verify configurable connection timeout for SlingClient
+ */
+public class SlingClientConnectionTimeoutTest {
+    private static final String GET_TIMEOUT_PATH = "/test/timeout/resource";
+    private static final String OK_RESPONSE = "TEST_OK";
+
+    @ClassRule
+    public static HttpServerRule httpServer = new HttpServerRule() {
+        @Override
+        protected void registerHandlers() throws IOException {
+            serverBootstrap.registerHandler(GET_TIMEOUT_PATH, new HttpRequestHandler() {
+                @Override
+                public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
+                    // block for 15 seconds
+                    try {
+                        Thread.sleep(TimeUnit.SECONDS.toMillis(15));
+                    } catch (InterruptedException e) {
+                        // ignore
+                    }
+                    response.setEntity(new StringEntity(OK_RESPONSE));
+                }
+            });
+        }
+    };
+
+    /**
+     * Test that a configured connection timeout will kill the client request when it
+     * does not respond quickly enough
+     */
+    @Test
+    public void testConnectionTimeout() throws Exception {
+        String originalValue = System.getProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, null);
+        try {
+            // timeout when the request takes more than 2 second
+            System.setProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, "2");
+            try (SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass")) {
+                // start the client request
+                c.doGet(GET_TIMEOUT_PATH);
+                
+                // should not get here
+                fail("Did not recieve the expected SocketTimeoutException");
+            }
+        } catch (Exception e) {
+            Throwable cause = e.getCause();
+            assertTrue("expected a SocketTimeoutException", cause instanceof SocketTimeoutException);
+        } finally {
+            //put the original value back
+            if (originalValue == null) {
+                System.clearProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP);
+            } else {
+                System.setProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, originalValue);
+            }
+        }        
+    }
+    
+    /**
+     * Test that when no connection timeout is supplied, the client connection waits
+     */
+    @Test
+    public void testConnectionNoTimeout() throws Exception {
+        String originalValue = System.getProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, null);
+        try {
+            // clear out any timeout configuration
+            System.clearProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP);
+
+            try (SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass")) {
+                SlingHttpResponse response = null;
+                CompletableFuture<SlingHttpResponse> endpointCall = CompletableFuture.supplyAsync(() -> {
+                    try {
+                        return c.doGet(GET_TIMEOUT_PATH);
+                    } catch (ClientException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    }
+                    return null;
+                });
+
+                try {
+                    response = endpointCall.get(2, TimeUnit.SECONDS);
+                    assertNull("Did not expect a response from the endpoint", response);
+                } catch (TimeoutException e) {
+                    // expected that we killed the future when it didn't finish
+                    //  on it's own in a timely manner
+                }            
+            }
+        } finally {
+            //put the original value back
+            if (originalValue == null) {
+                System.clearProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP);
+            } else {
+                System.setProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, originalValue);
+            }
+        }        
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java b/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java
index 05c1908..8d3ee85 100644
--- a/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java
+++ b/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java
@@ -16,21 +16,22 @@
  */
 package org.apache.sling.testing.clients;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
-import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Test;
 
-import java.io.IOException;
-import java.util.concurrent.TimeoutException;
-
-import static org.junit.Assert.*;
-
 public class SlingClientWaitExistsTest {
     private static final String GET_WAIT_PATH = "/test/wait/resource";
     private static final String OK_RESPONSE = "TEST_OK";
@@ -70,7 +71,7 @@
     @Test
     public void testWaitExistsTimeout() throws Exception {
         callCount = 0;  // reset counter
-        waitCount = 40;  // to be sure we reach timeout
+        waitCount = 200;  // to be sure we reach timeout
         SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass");
         try {
             c.waitExists(GET_WAIT_PATH, 1000, 10);