You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2016/04/29 16:03:33 UTC
svn commit: r1741632 [1/4] - in /sling/trunk/testing/http: ./ clients/
clients/src/ clients/src/main/ clients/src/main/java/
clients/src/main/java/org/ clients/src/main/java/org/apache/
clients/src/main/java/org/apache/sling/ clients/src/main/java/org/...
Author: bdelacretaz
Date: Fri Apr 29 14:03:32 2016
New Revision: 1741632
URL: http://svn.apache.org/viewvc?rev=1741632&view=rev
Log:
SLING-5703 - new http/clients module, extracted and enhanced from testing/tools. Contributed by Andrei Dulvac, thanks!
Added:
sling/trunk/testing/http/
sling/trunk/testing/http/clients/ (with props)
sling/trunk/testing/http/clients/README.md
sling/trunk/testing/http/clients/pom.xml
sling/trunk/testing/http/clients/src/
sling/trunk/testing/http/clients/src/main/
sling/trunk/testing/http/clients/src/main/java/
sling/trunk/testing/http/clients/src/main/java/org/
sling/trunk/testing/http/clients/src/main/java/org/apache/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/ClientException.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/Constants.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/SlingClient.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/SlingClientConfig.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/SlingHttpResponse.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/instance/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/instance/InstanceConfiguration.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/instance/InstanceSetup.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/DelayRequestInterceptor.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/StickyCookieHolder.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/StickyCookieInterceptor.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/StickyCookieSpec.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/TestDescriptionHolder.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/TestDescriptionInterceptor.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/interceptors/package-info.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/Bundle.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundleInfo.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInfo.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/Component.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/ComponentInfo.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/ComponentsInfo.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/OsgiInstanceConfig.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/WebconsoleClient.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/package-info.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/package-info.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/FormEntityBuilder.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/HttpUtils.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/InputStreamBodyWithLength.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/PortAllocator.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/ResourceUtil.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/SlingParameter.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/URLParameterBuilder.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/UniquePaths.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/XSSUtils.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfig.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigCache.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigException.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/impl/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/impl/EmptyInstanceConfig.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/impl/InstanceConfigCacheImpl.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/config/package-info.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/AbstractPoller.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/Poller.java
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/timeouts/
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/timeouts/TimeoutsProvider.java
sling/trunk/testing/http/clients/src/test/
sling/trunk/testing/http/clients/src/test/java/
sling/trunk/testing/http/clients/src/test/java/org/
sling/trunk/testing/http/clients/src/test/java/org/apache/
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/AbstractSlingClientGetPathTest.java
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/AbstractSlingClientGetServerUrlTest.java
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/AbstractSlingClientGetUrlTest.java
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/DelayRequestInterceptorTest.java
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/util/
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/util/UniquePathsTest.java
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/util/poller/
sling/trunk/testing/http/clients/src/test/java/org/apache/sling/testing/util/poller/AbstractPollerTest.java
Propchange: sling/trunk/testing/http/clients/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Apr 29 14:03:32 2016
@@ -0,0 +1,19 @@
+target
+sling
+bin
+logs
+jackrabbit-repository
+derby.log
+*.iml
+*.ipr
+*.iws
+.settings
+.project
+.classpath
+.externalToolBuilders
+maven-eclipse.xml
+jackrabbit
+
+
+
+
Added: sling/trunk/testing/http/clients/README.md
URL: http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/README.md?rev=1741632&view=auto
==============================================================================
--- sling/trunk/testing/http/clients/README.md (added)
+++ sling/trunk/testing/http/clients/README.md Fri Apr 29 14:03:32 2016
@@ -0,0 +1,211 @@
+# Sling Http Clients
+
+`SlingClient` is a specialized
+[`HttpClient`](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/HttpClient.html)
+that provides additional functionalities specific to Sling. It is designed to be easy to use out of the box, but also fully customizable.
+This library comes with a bunch of other specialized clients (built on top of `SlingClient`) that are ready to use.
+
+## <a name="architecture"></a> Architecture
+
+`SlingClient` implements the `HttpClient` interface, but [deletegates](https://en.wikipedia.org/wiki/Delegation_pattern)
+this functionality to a `private final CloseableHttpClient http` field.
+The config is stored in a `private final SlingClientConfig config` field which is immutable and may be shared across multiple clients
+(more about it in the [How to configure a SlingClient](#config) section).
+These two objects define the state of the client and are built to make the client thread safe.
+
+`SlingClient` is designed in two layers:
+* The base `class AbstractSlingClient implements HttpClient` provides an overlay of basic http methods such as `doGet()`,
+ `doPost()` & similar. These are meant to be full replacements of the ones in `HttpClient` for Sling specific needs,
+ and they add specific customizations. One particularity is that they all return `SlingHttpResponse`, an augmented `HttpResponse`.
+
+ Still, all the methods from `HttpClient` are exposed (through inheritance and delegation) in case one needs the raw functionality.
+ Some useful methods to manipulate Sling paths and URLs have also been added (`getUrl()`, `getPath()`).
+
+ This class encapsulates the mechanisms for extensibility (immutable config field, delegate client field, package private constructor,
+ `adaptTo()`), but it is defined as abstract and should never be used directly.
+
+* The main `class SlingClient extends AbstractSlingClient` is the one that adds Sling specific methods (`createNode()`,
+ `deletePath()` etc.). It has no fields, but makes use of everything that was defined in the super class.
+ Another main functionality defined in `SlingClient` are the mechanisms to instantiate a SlingClient (and any other sub-class):
+
+ * constructor: `public SlingClient(URI url, String user, String password) throws ClientException`
+
+ * builder: `public final static class Builder extends InternalBuilder<SlingClient>` (more in [How to write a `Builder`](#builder))
+
+Any client you write should extend `SlingClient` (more in [How to extend `SlingClient`](#extend))
+
+## <a name="instantiate"></a> How to instantiate `SlingClient`
+There are several ways to obtain a SlingClient (and sub-client) instance, depending on the resources available:
+
+* constructor `SlingClient(URI url, String user, String password)` - handy for obtaining a simple client from the url:
+ ```java
+ SlingClient c = new SlingClient(URI.create("localhost:8080"), "admin", "admin");
+ ```
+
+* builder `class Builder<T extends Builder> extends HttpClientBuilder` - this allows for more complex clients to be created, e.g.
+ with different authentication mechanism, or additional interceptors:
+ ```java
+ SlingClient c = SlingClient.Builder.create("localhost:8080", "admin", "admin").build();
+ ```
+ This gives the possibility to customize the HttpClient (e.g. add interceptors, change auth method) before constructing it.
+
+* `public <T extends AbstractSlingClient> T adaptTo(Class<T> clientClass)` is the convenient method to obtain another specialized
+client form an existing one. The advantage is that the two will share the same configuration and http handler, so they will behave
+like two different "facets" of the same client (think about the analogy of a Web browser with multiple tabs).
+
+Although the constructor and the builder are very handy, the preferred way of working with clients is to obtain it using one of the
+Junit Rules provided (e.g. `ExistingQuickstart`) and then call `adaptTo()`.
+
+## <a name="config"></a> How to configure `SlingClient`
+All the configs specific to `SlingClient` are stored in `private final SlingClientConfig config` which contains fields such as
+`url`, `cookieStore` and authentication parameters. These fields can be set only indirectly, through constructor or Builder, and only
+before constructing the client. They cannot be changed, so if you need to change something, you must instantiate another client.
+
+`SlingClient` was designed to be immutable, so thread safe. You don't have to worry about synchronizing it when running tests in parallel.
+Also, the immutable config is the base for the `adaptTo()` mechanism, since the two clients can share the same config.
+
+## <a name="extend"></a> How to extend `SlingClient`
+The `SlingClient` was designed with extensibility in mind. That's why it provides only basic functionality, leaving other specialized
+clients to implement the rest. To create a new client class (let's call it `MyClient`), you need to:
+* extend SlingClient: `class MyClient extends SlingClient`
+* implement the two constructors:
+ * the one for simple uses:
+ ```java
+ public MyClient(URI serverUrl, String userName, String password) throws ClientException {
+ super(serverUrl, userName, password);
+ }
+ ```
+ * the one used by `adaptTo()` (so don't forget it!):
+ ```java
+ public MyClient(CloseableHttpClient http, SlingClientConfig config) throws ClientException {
+ super(http, config);
+ }
+ ```
+ * optionally create your `Builder`, but only if needed (more in [How to write a `Builder`](#builder))
+
+A good example of how `SlingClient` can be extended is `OsgiConsoleClient`. Note you can further extend the sub-clients in the same way.
+
+## <a name="builder"></a> How to write a `Builder`
+If you need to make your client customizable you will have to write your own Builder (you were no thinking to break the immutability
+by adding a setter, right?). Below is an example of how to create the Builder mechanism that you can take and adapt for your needs.
+In this case, we try to expose only one field `foo`, but it can be extended to any number of fields. Although it seems complicated,
+if you follow exactly the example, you cannot fail. Trying to simplify it will burn you (sooner or later), you have been warned!
+
+A short description of the Builder architecture would be: the `InternalBuilder` contains all the logic while staying extensible, while
+`Builder` takes all the credit by exposing the `build()` method. Yet, the `Builder` cannot be extended because all the sub-classes would
+return a `SlingClient` when calling `build()` (and not a subclass instance).
+
+```java
+@Immutable
+public class MyClient extends SlingClient {
+
+ private final String foo;
+
+ public MyClient(URI serverUrl, String user, String password) throws ClientException {
+ super(serverUrl, user, password);
+ }
+
+ /**
+ * Constructor used by Builders and adaptTo(). <b>Should never be called directly from the code.</b>
+ *
+ * @see AbstractSlingClient#AbstractSlingClient(CloseableHttpClient, SlingClientConfig)
+ */
+ public MyClient(CloseableHttpClient http, SlingClientConfig config) throws ClientException {
+ super(http, config);
+ }
+
+ public static abstract class InternalBuilder<T extends MyClient> extends SlingClient.InternalBuilder<T> {
+ protected String foo;
+
+ protected InternalBuilder(URI url, String user, String password) {
+ super(url, user, password);
+ }
+
+ public InternalBuilder<T> withFoo(String foo) {
+ this.foo = foo;
+ }
+ }
+
+ public final static class Builder extends InternalBuilder<MyClient> {
+
+ private Builder(URI url, String user, String password) {
+ super(url, user, password);
+ }
+
+ @Override
+ public MyClient build() throws ClientException {
+ MyClient client = new MyClient(buildHttpClient(), buildSlingClientConfig());
+ client.foo = this.foo;
+ return client;
+ }
+
+ public static Builder create(URI url, String user, String password) {
+ return new Builder(url, user, password);
+ }
+ }
+}
+```
+
+## FAQ
+##### How can I change the server url of an existing client?
+You don't. As described in [How to configure a `SlingClient`](#config), you have to instantiate another client to change the config.
+
+##### How can I create a client for a server url with context path?
+The server `url` (passed in the constructor or builder) must contain all the elements, including protocol, hostname, port and eventually
+the context path, e.g.: `http://localhost:8080/mycontextpath/`.
+The url may (or may not) contain the trailing slash. Yet, the client will always store it with a trailing slash:
+```java
+SlingClient client = new SlingClient("http://localhost:4502/mycontextpath", "user", "pass");
+System.out.println(client.getUrl());
+// prints http://localhost:4502/mycontextpath/
+```
+
+##### How can I customize the underlying `HttpClient`?
+The `SlingClient.Builder` directly exposes the most useful methods from `HttpClientBuilder`, but not all of them.
+First, check if you can find it there. If you haven't found your specific method, then the `Builder` exposes an `HttpClientBuilder` through
+`public HttpClientBuilder httpClientBuilder()` which you can use to config it. Note that in this case you cannot chain the methods
+to build the client, so you will need to keep a reference to the `SlingClient.Builder`:
+```java
+SlingClient.Builder builder = SlingClient.Builder.create("http://localhost:8080", "user", "pass");
+HttpClientBuilder httpBuilder = builder.httpClientBuilder();
+httpBuilder.setProxy(myProxy);
+builder.setUser("another");
+SlingClient client = builder.build();
+```
+
+##### Why is the `Builder` pattern so complicated? Do I really need two classes?
+Don't try to get creative here. Respect the examples provided and don't take shortcuts, otherwise you will hurt yourself.
+
+We have tried different ways of designing the Builder. This is the best compromise between extensibility and simplicity. The
+`HttpClientBuilder` does not offer any extensibility support, so `SlingClient.Builder` does not extend it, it just uses it internally.
+Always remember that you don't need to create your Builder, unless you want to add custom fields to the client.
+
+##### Why I cannot use the entity's content InputStream?
+`SlingClient#doRequest()`, `SlingClient#doGet()`, `SlingClient#doPost()` & co. are all consuming the entity and caching it as
+String. This is by design, since there's a big risk to forget closing the connections and to run out of sockets quickly.
+If you need the response content as InputStream (e.g. for downloading a binary), you can use `doStreamGet()` or similar. These
+methods were written specially to not consume the entity so it's the caller's responsibility to close it when finished. Remember to use
+them with caution and only when needed.
+
+##### Can my client use another authentication method?
+The username and password required by the constructor and builder are there for convenience (since more than 90% of cases will use
+basic auth). But you can easily overwrite the `CredentialsProvider` in Builder so those will be ignored. Or do anything you want with
+that `HttpClientBuilder`...
+
+##### How can I obtain the context path?
+`client.getUrl().getPath()`
+
+##### How can I obtain the "relative" url (excluding hostname and port, but including context path)?
+`client.getUrl(path).getPath()`
+
+##### How can I remove the context path from a path?
+`client.getPath(path)`
+
+##### What if I pass an url or a path with or without context path to `getUrl()` or `getPath()`?
+We have tried to make these methods as robust as possible. Their job is very clear:
+* `getUrl(String path)` to transform a Sling path into a full url
+* `getPath(String url)` to transform a full url into a Sling path
+
+Any input that does not respect the contract might not work. Check `AbstractSlingClientGetPathTest` and `AbstractSlingClientGetUrlTest`
+for an extensive list of cases that we have considered when writing these methods.
+
Added: sling/trunk/testing/http/clients/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/pom.xml?rev=1741632&view=auto
==============================================================================
--- sling/trunk/testing/http/clients/pom.xml (added)
+++ sling/trunk/testing/http/clients/pom.xml Fri Apr 29 14:03:32 2016
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>26</version>
+ <relativePath />
+ </parent>
+
+ <artifactId>org.apache.sling.testing.clients</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>Apache Sling Testing Clients</name>
+ <description>
+ Sling testing http clients and utils
+ </description>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/http/clients</connection>
+ <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/http/clients</developerConnection>
+ <url>http://svn.apache.org/viewvc/sling/trunk/testing/http/clients</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.apache.sling.testing.clients.*,
+ </Export-Package>
+ <Import-Package>
+ org.apache.commons.exec.*; resolution:=optional,
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.tools</artifactId>
+ <version>1.0.12</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-exec</artifactId>
+ <version>1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>1.5.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>1.5.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ <version>4.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jsoup</groupId>
+ <artifactId>jsoup</artifactId>
+ <version>1.7.2</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>14.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.7.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.xss</artifactId>
+ <version>1.0.4</version>
+ </dependency>
+ </dependencies>
+</project>
Added: sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java?rev=1741632&view=auto
==============================================================================
--- sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java (added)
+++ sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java Fri Apr 29 14:03:32 2016
@@ -0,0 +1,715 @@
+/*
+ * 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 org.apache.http.*;
+import org.apache.http.annotation.Immutable;
+import org.apache.http.client.*;
+import org.apache.http.client.methods.*;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.protocol.HttpContext;
+import org.apache.sling.testing.clients.util.HttpUtils;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * The abstract base client for all implementing integration test clients.
+ */
+@Immutable
+public class AbstractSlingClient implements HttpClient {
+
+ private final org.slf4j.Logger log = LoggerFactory.getLogger(getClass());
+
+ private final static URI slash = URI.create("/");
+
+ /**
+ * The clientId for the client, generated automatically during instantiation of client.
+ */
+ private final String clientId;
+
+ /**
+ * The HttpClient object to which http calls are delegated.
+ * It can be shared across multiple AbstractSlingClients (by using adaptTo())
+ */
+ private final CloseableHttpClient http;
+
+ /**
+ * A wrapper object containing the sling config for this client.
+ * It can be shared across multiple AbstractSlingClients (by using adaptTo())
+ */
+ private final SlingClientConfig config;
+
+ /**
+ * Constructor used by Builders and adaptTo(). <b>Should never be called directly from the code.</b>
+ *
+ * @param http http client to handle the delegated calls
+ * @param config immutable object holding the config
+ * @throws ClientException if the client could not be initialized
+ */
+ AbstractSlingClient(CloseableHttpClient http, SlingClientConfig config) throws ClientException {
+ // Generate client ID
+ this.clientId = this.getClass() + "-" + UUID.randomUUID().toString();
+ this.http = http;
+ this.config = config;
+ }
+
+ /**
+ * Returns the unique id for this client, generated automatically during instantiation.<br>
+ *
+ * @return client's unique id
+ */
+ protected String getClientId() {
+ return clientId;
+ }
+
+ /**
+ * <p>Base HTTP URI of the server under test. It includes the context path, if present, and always ends with a slash</p>
+ * <p>Example: {@code http://localhost:8080/a/}</p>
+ *
+ * @return the server's URL
+ */
+ public URI getUrl() {
+ return config.getUrl();
+ }
+
+
+ /**
+ * Returns the name of the user that will be used to authenticate the requests (by basic auth, if not replaced).
+ *
+ * @return user's name
+ */
+ public String getUser() {
+ return config.getUser();
+ }
+
+ /**
+ * Returns the password of the user that will be used to authenticate the requests (by basic auth, if not replaced).
+ *
+ * @return user's password
+ */
+ public String getPassword() {
+ return config.getPassword();
+ }
+
+ /**
+ * <p>Gets the full URL for a given path.</p>
+ *
+ * <p>The input path is considered relative to server url path ("/" or context path), even though it starts with a slash.
+ * The path is relativized and appended to the {@code server url}.</p>
+ *
+ * <p>Note: in the case of a server url with context path - the input path should not contain the context path, otherwise
+ * it will be duplicated in the resulting url</p>
+ *
+ * @param path the relative path
+ * @return the absolute URI
+ * @throws IllegalArgumentException if path cannot be parsed into an URI
+ * @throws NullPointerException if path is null
+ */
+ public URI getUrl(String path) {
+ try {
+ URI pathUri = slash.relativize(new URI(path));
+ return getUrl().resolve(pathUri);
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Creates a full URL for a given path with additional parameters. Same as {@link #getUrl(String)}, but adds the parameters in the URI.
+ *
+ * @param path path relative to server url; can start with / but should not include the server context path
+ * @param parameters url parameters to be added to the url
+ * @return full url as URI
+ * @throws IllegalArgumentException if path or parameters cannot be parsed into an URI
+ * @throws NullPointerException if path is null
+ */
+ public URI getUrl(String path, List<NameValuePair> parameters) {
+ // add server url and path
+ URIBuilder uriBuilder = new URIBuilder(getUrl(path));
+ // add parameters
+ parameters = (parameters != null) ? parameters : new ArrayList<NameValuePair>(0);
+ uriBuilder.addParameters(parameters);
+
+ try {
+ return uriBuilder.build();
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * <p>Transforms an external {@code url} into a sling path, by subtracting the {@code server url} (incl. contextPath).
+ * The returned path will not contain the context path, so it can be used with {@link #getUrl(String)}</p>
+ *
+ * <p>The url can be absolute (incl. hostname) or relative to root (starts with "/").</p>
+ *
+ * <p>If the server url is not a prefix of the given url, it returns the given url</p>
+ *
+ * <p>If the url is just a path, it returns the path (with leading slash if not already present)</p>
+ *
+ * @param url full url
+ * @return sling path
+ */
+ public URI getPath(URI url) {
+ // special case for urls that are server urls, but without trailing slash
+ if (url.relativize(getUrl()).equals(URI.create(""))) {
+ return slash;
+ }
+
+ URI contextPath = URI.create(getUrl().getPath());
+ URI relativeUrl = contextPath.relativize(slash.resolve(url));
+
+ if (relativeUrl.relativize(contextPath).equals(URI.create(""))) {
+ return slash;
+ }
+
+ return slash.resolve(getUrl().relativize(relativeUrl));
+ }
+
+ /**
+ * Extracts the relative sling path (to server url) from an url. Identical to {@link AbstractSlingClient#getPath(URI)},
+ * except that it also parses the String int URI
+ *
+ * @param url string containing the full url
+ * @return relative path as URI
+ * @throws IllegalArgumentException if the parameter cannot be parsed
+ * @throws NullPointerException if url is null
+ */
+ public URI getPath(String url) {
+ try {
+ return getPath(new URI(url));
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * <p>Returns an instance of any class extending the AbstractSlingClient. The new client will
+ * use the the same {@link HttpClient} and {@link SlingClientConfig} </p>
+ *
+ * @param clientClass the type of client requested, identified by its Class
+ * @param <T> any class extending the AbstractSlingClient
+ * @return instance of a class extending the AbstractSlingClient
+ * @throws ClientException if client can't be instantiated
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends AbstractSlingClient> T adaptTo(Class<T> clientClass) throws ClientException {
+ T client;
+ try {
+ Constructor cons = clientClass.getConstructor(CloseableHttpClient.class, SlingClientConfig.class);
+ client = (T) cons.newInstance(this.http, this.config);
+ } catch (Exception e) {
+ throw new ClientException("Could not initialize client: '" + clientClass.getCanonicalName() + "'.", e);
+ }
+ return client;
+ }
+
+ /**
+ * Gets the value for {@code key} from the generic values
+ *
+ * @param key the key
+ * @return the value
+ */
+ public String getValue(String key) {
+ return this.config.getValues().get(key);
+ }
+
+ /**
+ * Adds the extra {@code key, value} to the generic values
+ *
+ * @param key the key for witch to add a value
+ * @param value the value
+ */
+ public void addValue(String key, String value) {
+ this.config.getValues().put(key, value);
+ }
+
+ /**
+ * Checks whether the handler has the given generic value
+ *
+ * @param key the key
+ * @return true if the value was found
+ */
+ public boolean hasValue(String key) {
+ return config.getValues().containsKey(key);
+ }
+
+ /**
+ * Returns the extra values map
+ *
+ * @return the map of values
+ */
+ public Map<String, String> getValues() {
+ return config.getValues();
+ }
+
+ /**
+ * @return the cookie store reference
+ */
+ public CookieStore getCookieStore() {
+ return config.getCookieStore();
+ }
+
+ /**
+ * @return the credentials provider
+ */
+ public CredentialsProvider getCredentialsProvider() {
+ return config.getCredsProvider();
+ }
+
+ //
+ // HTTP convenience methods
+ //
+
+ /**
+ * <p>Executes an HTTP request, WITHOUT consuming the entity in the response. The caller is responsible for consuming the entity or
+ * closing the response's InputStream in order to release the connection.
+ * Otherwise, the client might run out of connections and will block</p>
+ *
+ * <p><b>Use this with caution and only if necessary for streaming</b>, otherwise use the safe method
+ * {@link #doRequest(HttpUriRequest, List, int...)}</p>
+ *
+ * <p>Adds the headers and checks the response against expected status</p>
+ *
+ * @param request the request to be executed
+ * @param headers optional headers to be added to the request
+ * @param expectedStatus if passed, the response status is checked against it/them, and has to match at least one of them
+ * @return the response, with the entity not consumed
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doStreamRequest(HttpUriRequest request, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ // create context from config
+ HttpClientContext context = createHttpClientContextFromConfig();
+
+ // add headers
+ if (headers != null) {
+ request.setHeaders(headers.toArray(new Header[headers.size()]));
+ }
+
+ try {
+ log.debug("request {} {}", request.getMethod(), request.getURI());
+ SlingHttpResponse response = new SlingHttpResponse(this.execute(request, context));
+ log.debug("response {}", HttpUtils.getHttpStatus(response));
+ // Check the status and throw a ClientException if it doesn't match expectedStatus, but close the entity before
+ if (expectedStatus != null && expectedStatus.length > 0) {
+ try {
+ HttpUtils.verifyHttpStatus(response, expectedStatus);
+ } catch (ClientException e) {
+ // catch the exception to make sure we close the entity before re-throwing it
+ response.close();
+ throw e;
+ }
+ }
+
+ return response;
+ } catch (IOException e) {
+ throw new ClientException("Could not execute http request", e);
+ }
+ }
+
+ /**
+ * <p>Executes a raw HTTP request, WITHOUT consuming the entity in the response. The caller is responsible for consuming the entity or
+ * closing the response's InputStream in order to release the connection.
+ * Otherwise, the client might run out of connections and will block</p>
+ *
+ * <p><b>Use this with caution and only if necessary for custom methods or for paths that must not be encoded</b>,
+ * otherwise use the safe method {@link #doRequest(HttpUriRequest, List, int...)}</p>
+ *
+ * <p>It behaves as {@link #doStreamRequest(HttpUriRequest, List, int...)}, so the entity is not consumed.</p>
+ * <p>Adds the headers and checks the response against expected status</p>
+ *
+ * @param method the request to be executed
+ * @param uri the uri to be sent as it is (will not prepend the context path)
+ * @param headers optional headers to be added to the request
+ * @param expectedStatus if passed, the response status is checked against it/them, and has to match at least one of them
+ * @return the response, with the entity not consumed
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doRawRequest(String method, String uri, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ // create context from config
+ HttpClientContext context = createHttpClientContextFromConfig();
+
+ HttpHost host = new HttpHost(getUrl().getHost(), getUrl().getPort(), getUrl().getScheme());
+ HttpRequest request = new BasicHttpRequest(method, uri);
+
+ // add headers
+ if (headers != null) {
+ request.setHeaders(headers.toArray(new Header[headers.size()]));
+ }
+
+ try {
+ log.debug("request {} {}", method, uri);
+ SlingHttpResponse response = new SlingHttpResponse(this.execute(host, request, context));
+ log.debug("response {}", HttpUtils.getHttpStatus(response));
+ // Check the status and throw a ClientException if it doesn't match expectedStatus, but close the entity before
+ if (expectedStatus != null && expectedStatus.length > 0) {
+ try {
+ HttpUtils.verifyHttpStatus(response, expectedStatus);
+ } catch (ClientException e) {
+ // catch the exception to make sure we close the entity before re-throwing it
+ response.close();
+ throw e;
+ }
+ }
+
+ return response;
+ } catch (IOException e) {
+ throw new ClientException("Could not execute http request", e);
+ }
+ }
+
+ private HttpClientContext createHttpClientContextFromConfig() {
+ // create context from config
+ HttpClientContext context = HttpClientContext.create();
+
+ if (config.getCookieStore() != null) {
+ context.setCookieStore(config.getCookieStore());
+ }
+
+ if (config.getCredsProvider() != null) {
+ context.setCredentialsProvider(config.getCredsProvider());
+ }
+
+ if (config.getAuthCache() != null) {
+ context.setAuthCache(config.getAuthCache());
+ }
+
+ return context;
+ }
+
+ /**
+ * <p>Executes a GET request WITHOUT consuming the entity in the response. The caller is responsible to close the connection.
+ * Otherwise, the client might run out of connections and will block</p>
+ *
+ * <p><b>Use this with caution and only if necessary for streaming</b>, otherwise use the safe method
+ * {@link #doGet(String, List, List, int...)}</p>
+ *
+ * <p>Adds the given parameters and headers and checks the response against expected status</p>
+ * @param requestPath path relative to client url
+ * @param parameters optional url parameters to be added
+ * @param headers optional headers to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity not consumed
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doStreamGet(String requestPath, List<NameValuePair> parameters, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ // create full uri, including server url, given path and given parameters
+ URI uri = getUrl(requestPath, parameters);
+ // execute request
+ HttpUriRequest request = new HttpGet(uri);
+ return doStreamRequest(request, headers, expectedStatus);
+ }
+
+ /**
+ * <p>Executes a POST request WITHOUT consuming the entity in the response. The caller is responsible to close the connection</p>
+ *
+ * <p><b>Use this with caution and only if necessary for streaming</b>, otherwise use the safe method
+ * {@link #doPost(String, HttpEntity, List, int...)}</p>
+ *
+ * <p>Adds the headers and checks the response against expected status</p>
+ * @param requestPath path relative to client url
+ * @param entity http entity to be sent by POST
+ * @param headers optional headers to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity not consumed
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doStreamPost(String requestPath, HttpEntity entity, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ HttpEntityEnclosingRequestBase request = new HttpPost(getUrl(requestPath));
+ if (entity != null) {
+ request.setEntity(entity);
+ }
+ return doStreamRequest(request, headers, expectedStatus);
+ }
+
+ /**
+ * <p>Execute an HTTP request and consumes the entity in the response. The content is cached and can be retrieved using
+ * {@code response.getContent()}.
+ * This method is safe to use because it closes the entity so the caller has no responsibility.</p>
+ *
+ * <p>This means the response entity SHOULD NOT BE USED to read the content, e.g. {@code response.getEntity().getContent()}</p>
+ *
+ * @param request the request to be executed
+ * @param headers optional headers to be added to the request
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed and the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doRequest(HttpUriRequest request, List<Header> headers, int... expectedStatus) throws ClientException {
+ SlingHttpResponse response = doStreamRequest(request, headers, expectedStatus);
+
+ // Consume entity and cache the content so the connection is closed
+ response.getContent();
+
+ return response;
+ }
+
+ /**
+ * <p>Executes a GET request and consumes the entity in the response (so the connection is closed immediately)
+ * The content is cached and can be retrieved using {@code response.getContent()}.</p>
+ *
+ * <p>Adds the passed parameters and headers and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param parameters optional url parameters to be added
+ * @param headers optional headers to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed amd the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doGet(String requestPath, List<NameValuePair> parameters, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ SlingHttpResponse response = doStreamGet(requestPath, parameters, headers, expectedStatus);
+
+ // Consume entity and cache the content so the connection is closed
+ response.getContent();
+
+ return response;
+ }
+
+ /**
+ * <p>Executes a GET request and consumes the entity in the response (so the connection is closed immediately)
+ * The content is cached and can be retrieved using {@code response.getContent()}.</p>
+ *
+ * <p>Adds the passed parameters and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param parameters optional url parameters to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed amd the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doGet(String requestPath, List<NameValuePair> parameters, int... expectedStatus)
+ throws ClientException {
+ return doGet(requestPath, parameters, null, expectedStatus);
+ }
+
+ /**
+ * <p>Executes a GET request and consumes the entity in the response (so the connection is closed immediately)
+ * The content is cached and can be retrieved using {@code response.getContent()}.</p>
+ *
+ * @param requestPath path relative to client url
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed amd the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doGet(String requestPath, int... expectedStatus)
+ throws ClientException {
+ return doGet(requestPath, null, null, expectedStatus);
+ }
+
+ /**
+ * <p>Executes a HEAD request</p>
+ *
+ * <p>Adds the passed parameters and headers and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param parameters optional url parameters to be added
+ * @param headers optional headers to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doHead(String requestPath, List<NameValuePair> parameters, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ HttpUriRequest request = new HttpHead(getUrl(requestPath, parameters));
+ return doRequest(request, headers, expectedStatus);
+ }
+
+
+ /**
+ * <p>Executes a POST request and consumes the entity in the response. The content is cached and be retrieved by calling
+ * {@code response.getContent()}</p>
+ *
+ * <p>Adds the passed entity and headers and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param entity the entity to be added to request
+ * @param headers optional headers to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed and the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doPost(String requestPath, HttpEntity entity, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ HttpEntityEnclosingRequestBase request = new HttpPost(getUrl(requestPath));
+ if (entity != null) {
+ request.setEntity(entity);
+ }
+ return doRequest(request, headers, expectedStatus);
+ }
+
+ /**
+ * <p>Executes a POST request and consumes the entity in the response. The content is cached and be retrieved by calling
+ * {@code response.getContent()}</p>
+ *
+ * <p>Adds the passed entity and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param entity the entity to be added to request
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed and the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doPost(String requestPath, HttpEntity entity, int... expectedStatus)
+ throws ClientException {
+ return doPost(requestPath, entity, null, expectedStatus);
+ }
+
+ /**
+ * <p>Executes a PUT request and consumes the entity in the response. The content is cached and be retrieved by calling
+ * {@code response.getContent()}</p>
+ *
+ * <p>Adds the passed entity and headers and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param entity the entity to be added to request
+ * @param headers optional url parameters to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed and the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doPut(String requestPath, HttpEntity entity, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ HttpEntityEnclosingRequestBase request = new HttpPut(getUrl(requestPath));
+ if (entity != null) {
+ request.setEntity(entity);
+ }
+ return doRequest(request, headers, expectedStatus);
+ }
+
+ /**
+ * <p>Executes a PATCH request and consumes the entity in the response. The content is cached and be retrieved by calling
+ * {@code response.getContent()}</p>
+ *
+ * <p>Adds the passed entity and headers and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param entity the entity to be added to request
+ * @param headers optional url parameters to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed and the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doPatch(String requestPath, HttpEntity entity, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ HttpEntityEnclosingRequestBase request = new HttpPatch(getUrl(requestPath));
+ if (entity != null) {
+ request.setEntity(entity);
+ }
+ return doRequest(request, headers, expectedStatus);
+ }
+
+ /**
+ * <p>Executes a DELETE request and consumes the entity in the response. The content is cached and be retrieved by calling
+ * {@code response.getContent()}</p>
+ *
+ * <p>Adds the passed parameters and headers and checks the expected status</p>
+ *
+ * @param requestPath path relative to client url
+ * @param parameters optional url parameters to be added
+ * @param headers optional url parameters to be added
+ * @param expectedStatus if passed, the response status will have to match one of them
+ * @return the response with the entity consumed and the content cached
+ * @throws ClientException if the request could not be executed
+ */
+ public SlingHttpResponse doDelete(String requestPath, List<NameValuePair> parameters, List<Header> headers, int... expectedStatus)
+ throws ClientException {
+ HttpUriRequest request = new HttpDelete(getUrl(requestPath, parameters));
+ return doRequest(request, headers, expectedStatus);
+ }
+
+
+ //
+ // HttpClient base methods
+ //
+
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public org.apache.http.params.HttpParams getParams() {
+ return this.http.getParams();
+ }
+
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public org.apache.http.conn.ClientConnectionManager getConnectionManager() {
+ return this.http.getConnectionManager();
+ }
+
+ @SuppressWarnings("DuplicateThrows")
+ public HttpResponse execute(HttpUriRequest request) throws IOException, ClientProtocolException {
+ return this.http.execute(request);
+ }
+
+ // maybe throw UnsupportedMethodException
+ @SuppressWarnings("DuplicateThrows")
+ public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context)
+ throws IOException, ClientProtocolException {
+ return this.http.execute(request, context);
+ }
+
+ @SuppressWarnings("DuplicateThrows")
+ public HttpResponse execute(HttpHost target, HttpRequest request)
+ throws IOException, ClientProtocolException {
+ return this.http.execute(target, request);
+ }
+
+ @SuppressWarnings("DuplicateThrows")
+ public CloseableHttpResponse execute(HttpHost target, HttpRequest request, HttpContext context)
+ throws IOException, ClientProtocolException {
+ return this.http.execute(target, request, context);
+ }
+
+ @SuppressWarnings("DuplicateThrows")
+ public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler)
+ throws IOException, ClientProtocolException {
+ return this.http.execute(request, responseHandler);
+ }
+
+ @SuppressWarnings("DuplicateThrows")
+ public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context)
+ throws IOException, ClientProtocolException {
+ return this.http.execute(request, responseHandler, context);
+ }
+
+ @SuppressWarnings("DuplicateThrows")
+ public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler)
+ throws IOException, ClientProtocolException {
+ return this.http.execute(target, request, responseHandler);
+ }
+
+ @SuppressWarnings("DuplicateThrows")
+ public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context)
+ throws IOException, ClientProtocolException {
+ return this.http.execute(target, request, responseHandler, context);
+ }
+}
Added: sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/ClientException.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/ClientException.java?rev=1741632&view=auto
==============================================================================
--- sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/ClientException.java (added)
+++ sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/ClientException.java Fri Apr 29 14:03:32 2016
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+/**
+ *
+ */
+public class ClientException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+ private int httpStatusCode = -1;
+
+ public ClientException(String message) {
+ this(message, null);
+ }
+
+ public ClientException(String message, Throwable throwable) {
+ this(message, -1, throwable);
+ }
+
+ public ClientException(String message, int htmlStatusCode, Throwable throwable) {
+ super(message, throwable);
+ this.httpStatusCode = htmlStatusCode;
+ }
+
+ /**
+ * @return the htmlStatusCode
+ */
+ public int getHttpStatusCode() {
+ return httpStatusCode;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Throwable#getMessage()
+ */
+ @Override
+ public String getMessage() {
+ String message = super.getMessage();
+ if (httpStatusCode > -1) {
+ message = message + "(return code=" + httpStatusCode + ")";
+ }
+ return message;
+ }
+
+}
Added: sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/Constants.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/Constants.java?rev=1741632&view=auto
==============================================================================
--- sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/Constants.java (added)
+++ sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/Constants.java Fri Apr 29 14:03:32 2016
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+public class Constants {
+
+ /**
+ * Prefix for IT-specific system properties
+ */
+ public static final String CONFIG_PROP_PREFIX = "sling.it.";
+ public static final String DEFAULT_URL = "http://localhost:8080/";
+ public static final String DEFAULT_USERNAME = "admin";
+ public static final String DEFAULT_PASSWORD = "admin";
+
+ // Custom delay for requests
+ private static long delay;
+ static {
+ try {
+ Constants.delay = Long.getLong(Constants.CONFIG_PROP_PREFIX + "http.delay", 0);
+ } catch (NumberFormatException e) {
+ Constants.delay = 0;
+ }
+ }
+
+ /**
+ * Custom delay in milliseconds before an HTTP request goes through.
+ * Used by {@link org.apache.sling.testing.clients.interceptors.DelayRequestInterceptor}
+ */
+ public static final long HTTP_DELAY = delay;
+
+ /**
+ * Handle to OSGI console
+ */
+ public static final String OSGI_CONSOLE = "/system/console";
+
+ /**
+ * General parameters and values
+ */
+ public static final String PARAMETER_CHARSET = "_charset_";
+ public static final String CHARSET_UTF8 = "utf-8";
+}