merge with branch issue-709

This commit is contained in:
Sebastian Sdorra
2015-05-17 14:06:43 +02:00
47 changed files with 5013 additions and 101 deletions

View File

@@ -48,7 +48,10 @@ import java.util.Map;
* @apiviz.landmark
* @apiviz.uses sonia.scm.net.HttpRequest
* @apiviz.uses sonia.scm.net.HttpResponse
*
* @deprecated use {@link sonia.scm.net.ahc.AdvancedHttpClient} instead.
*/
@Deprecated
public interface HttpClient
{

View File

@@ -51,7 +51,11 @@ import java.util.Map;
*
* @author Sebastian Sdorra
* @since 1.9
*
* @deprecated use {@link sonia.scm.net.ahc.AdvancedHttpRequest} or
* {@link sonia.scm.net.ahc.AdvancedHttpRequestWithBody} instead.
*/
@Deprecated
public class HttpRequest
{

View File

@@ -41,12 +41,16 @@ import java.io.InputStream;
import java.util.List;
import java.util.Map;
import sonia.scm.net.ahc.AdvancedHttpResponse;
/**
* Response of a {@link HttpRequest} execute by the {@link HttpClient}.
*
* @author Sebastian Sdorra
*
* @deprecated use {@link AdvancedHttpResponse} instead
*/
@Deprecated
public interface HttpResponse extends Closeable
{

View File

@@ -0,0 +1,202 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
/**
* Advanced client for http operations. The {@link AdvancedHttpClient} replaces
* the much more simpler implementation {@link sonia.scm.net.HttpClient}. The
* {@link AdvancedHttpClient} offers a fluid interface for handling most common
* http operations. The {@link AdvancedHttpClient} can be injected by the
* default injection mechanism of SCM-Manager.
* <p>&nbsp;</p>
* <b>Http GET example:</b>
*
* <pre><code>
* AdvancedHttpResponse response = client.get("https://www.scm-manager.org")
* .decodeGZip(true)
* .request();
*
* System.out.println(response.contentAsString());
* </code></pre>
*
* <p>&nbsp;</p>
* <b>Http POST example:</b>
*
* <pre><code>
* AdvancedHttpResponse response = client.post("https://www.scm-manager.org")
* .formContent()
* .field("firstname", "Tricia")
* .field("lastname", "McMillan")
* .build()
* .request();
*
* if (response.isSuccessful()){
* System.out.println("success");
* }
* </code></pre>
*
* @author Sebastian Sdorra
* @since 1.46
*
* @apiviz.landmark
*/
public abstract class AdvancedHttpClient
{
/**
* Creates a {@link ContentTransformer} for the given Content-Type.
*
* @param type object type
* @param contentType content-type
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return {@link ContentTransformer}
*/
protected abstract ContentTransformer createTransformer(Class<?> type,
String contentType);
/**
* Executes the given request and returns the http response. Implementation
* have to check, if the instance if from type
* {@link AdvancedHttpRequestWithBody} in order to handle request contents.
*
*
* @param request request to execute
*
* @return http response
*
* @throws IOException
*/
protected abstract AdvancedHttpResponse request(BaseHttpRequest<?> request)
throws IOException;
/**
* Returns a builder for a DELETE request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody delete(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.DELETE, url);
}
/**
* Returns a builder for a HEAD request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequest head(String url)
{
return new AdvancedHttpRequest(this, HttpMethod.HEAD, url);
}
/**
* Returns a request builder with a custom method. <strong>Note:</strong> not
* every method is supported by the underlying implementation of the http
* client.
*
*
* @param method http method
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody method(String method, String url)
{
return new AdvancedHttpRequestWithBody(this, method, url);
}
/**
* Returns a builder for a OPTIONS request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody options(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.OPTIONS, url);
}
/**
* Returns a builder for a POST request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody post(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.POST, url);
}
/**
* Returns a builder for a PUT request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody put(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.PUT, url);
}
//~--- get methods ----------------------------------------------------------
/**
* Returns a builder for a GET request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequest get(String url)
{
return new AdvancedHttpRequest(this, HttpMethod.GET, url);
}
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
/**
* An http request without {@link Content} for example a GET or HEAD request.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class AdvancedHttpRequest extends BaseHttpRequest<AdvancedHttpRequest>
{
/**
* Constructs a new {@link AdvancedHttpRequest}
*
*
* @param client
* @param method
* @param url
*/
AdvancedHttpRequest(AdvancedHttpClient client, String method,
String url)
{
super(client, method, url);
}
//~--- methods --------------------------------------------------------------
/**
* Returns {@code this}.
*
*
* @return {@code this}
*/
@Override
protected AdvancedHttpRequest self()
{
return this;
}
}

View File

@@ -0,0 +1,271 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.io.ByteSource;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.nio.charset.Charset;
/**
* Http request with body.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class AdvancedHttpRequestWithBody
extends BaseHttpRequest<AdvancedHttpRequestWithBody>
{
/**
* Constructs a new {@link AdvancedHttpRequestWithBody}.
*
*
* @param client http client
* @param method http method
* @param url url
*/
AdvancedHttpRequestWithBody(AdvancedHttpClient client, String method,
String url)
{
super(client, method, url);
}
//~--- methods --------------------------------------------------------------
/**
* Sets the content length for the request.
*
*
* @param length content length
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody contentLength(long length)
{
return header("Content-Length", String.valueOf(length));
}
/**
* Sets the content type for the request.
*
*
* @param contentType content type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody contentType(String contentType)
{
return header("Content-Type", contentType);
}
/**
* Sets the content of the file as request content.
*
*
* @param file file
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody fileContent(File file)
{
this.content = new FileContent(file);
return this;
}
/**
* Returns a {@link FormContentBuilder}. The builder can be used to add form
* parameters as content for the request. <strong>Note:</strong> you have to
* call {@link FormContentBuilder#build()} in order to apply the form content
* to the request.
*
* @return form content builder
*/
public FormContentBuilder formContent()
{
return new FormContentBuilder(this);
}
/**
* Transforms the given object to a xml string and set this string as request
* content.
*
* @param object object to transform
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the json content-type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody jsonContent(Object object)
{
return transformedContent(ContentType.JSON, object);
}
/**
* Sets the raw data as request content.
*
*
* @param data raw data
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody rawContent(byte[] data)
{
this.content = new RawContent(data);
return this;
}
/**
* Sets the raw data as request content.
*
*
* @param source byte source
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody rawContent(ByteSource source)
{
this.content = new ByteSourceContent(source);
return this;
}
/**
* Sets the string as request content.
*
*
* @param content string content
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody stringContent(String content)
{
return stringContent(content, Charsets.UTF_8);
}
/**
* Sets the string as request content.
*
*
* @param content string content
* @param charset charset of content
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody stringContent(String content,
Charset charset)
{
this.content = new StringContent(content, charset);
return this;
}
/**
* Transforms the given object to a string and set this string as request
* content. The content-type is used to pick the right
* {@link ContentTransformer}. The method will throw an exception if no
* {@link ContentTransformer} for the content-type could be found.
*
* @param contentType content-type
* @param object object to transform
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the given content-type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody transformedContent(String contentType,
Object object)
{
ContentTransformer transformer =
client.createTransformer(object.getClass(), contentType);
ByteSource value = transformer.marshall(object);
contentType(contentType);
return rawContent(value);
}
/**
* Transforms the given object to a xml string and set this string as request
* content.
*
* @param object object to transform
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the xml content-type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody xmlContent(Object object)
{
return transformedContent(ContentType.XML, object);
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the content or the request.
*
*
* @return request content
*/
public Content getContent()
{
return content;
}
//~--- methods --------------------------------------------------------------
/**
* Returns {@code this}.
*
*
* @return {@code this}
*/
@Override
protected AdvancedHttpRequestWithBody self()
{
return this;
}
//~--- fields ---------------------------------------------------------------
/** request content */
private Content content;
}

View File

@@ -0,0 +1,312 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
//~--- JDK imports ------------------------------------------------------------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
/**
* Http response. The response of a {@link AdvancedHttpRequest} or
* {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public abstract class AdvancedHttpResponse
{
/**
* Returns the response content as byte source.
*
*
* @return response content as byte source
* @throws IOException
*/
public abstract ByteSource contentAsByteSource() throws IOException;
//~--- get methods ----------------------------------------------------------
/**
* Returns the response headers.
*
*
* @return response headers
*/
public abstract Multimap<String, String> getHeaders();
/**
* Returns the status code of the response.
*
*
* @return status code
*/
public abstract int getStatus();
/**
* Returns the status text of the response.
*
*
* @return status text
*/
public abstract String getStatusText();
//~--- methods --------------------------------------------------------------
/**
* Creates a {@link ContentTransformer} for the given Content-Type.
*
* @param type object type
* @param contentType content-type
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return {@link ContentTransformer}
*/
protected abstract ContentTransformer createTransformer(Class<?> type,
String contentType);
/**
* Returns the content of the response as byte array.
*
*
* @return content as byte array
*
* @throws IOException
*/
public byte[] content() throws IOException
{
ByteSource content = contentAsByteSource();
byte[] data = null;
if (content != null)
{
data = content.read();
}
return data;
}
/**
* Returns a reader for the content of the response.
*
*
* @return read of response content
*
* @throws IOException
*/
public BufferedReader contentAsReader() throws IOException
{
ByteSource content = contentAsByteSource();
BufferedReader reader = null;
if (content != null)
{
reader = content.asCharSource(Charsets.UTF_8).openBufferedStream();
}
return reader;
}
/**
* Returns response content as stream.
*
*
* @return response content as stram
*
* @throws IOException
*/
public InputStream contentAsStream() throws IOException
{
ByteSource content = contentAsByteSource();
InputStream stream = null;
if (content != null)
{
stream = content.openBufferedStream();
}
return stream;
}
/**
* Returns the response content as string.
*
*
* @return response content
*
* @throws IOException
*/
public String contentAsString() throws IOException
{
ByteSource content = contentAsByteSource();
String value = null;
if (content != null)
{
value = content.asCharSource(Charsets.UTF_8).read();
}
return value;
}
/**
* Transforms the response content from json to the given type.
*
* @param <T> object type
* @param type object type
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the json content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentFromJson(Class<T> type) throws IOException
{
return contentTransformed(type, ContentType.JSON);
}
/**
* Transforms the response content from xml to the given type.
*
* @param <T> object type
* @param type object type
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the xml content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentFromXml(Class<T> type) throws IOException
{
return contentTransformed(type, ContentType.XML);
}
/**
* Transforms the response content to the given type. The method uses the
* content-type header to pick the right {@link ContentTransformer}.
*
* @param <T> object type
* @param type object type
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentTransformed(Class<T> type) throws IOException
{
String contentType = getFirstHeader("Content-Type");
if (Strings.isNullOrEmpty(contentType))
{
throw new ContentTransformerException(
"response does not return a Content-Type header");
}
return contentTransformed(type, contentType);
}
/**
* Transforms the response content from xml to the given type.
*
* @param <T> object type
* @param type object type
* @param contentType type to pick {@link ContentTransformer}
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentTransformed(Class<T> type, String contentType)
throws IOException
{
T object = null;
ByteSource source = contentAsByteSource();
if (source != null)
{
ContentTransformer transformer = createTransformer(type, contentType);
object = transformer.unmarshall(type, contentAsByteSource());
}
return object;
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the first header value for the given header name or {@code null}.
*
*
* @param name header name
*
* @return header value or {@code null}
*/
public String getFirstHeader(String name)
{
return Iterables.getFirst(getHeaders().get(name), null);
}
/**
* Returns {@code true} if the response was successful. A response is
* successful, if the status code is greater than 199 and lower than 400.
*
* @return {@code true} if the response was successful
*/
public boolean isSuccessful()
{
int status = getStatus();
return (status > 199) && (status < 400);
}
}

View File

@@ -0,0 +1,409 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import org.apache.shiro.codec.Base64;
import sonia.scm.util.HttpUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
/**
* Base class for http requests.
*
* @author Sebastian Sdorra
* @param <T> request implementation
*
* @since 1.46
*/
public abstract class BaseHttpRequest<T extends BaseHttpRequest>
{
/**
* Constructs a new {@link BaseHttpRequest}.
*
*
* @param client http client
* @param method http method
* @param url url
*/
public BaseHttpRequest(AdvancedHttpClient client, String method, String url)
{
this.client = client;
this.method = method;
this.url = url;
}
//~--- methods --------------------------------------------------------------
/**
* Executes the request and returns the http response.
*
*
* @return http response
*
* @throws IOException
*/
public AdvancedHttpResponse request() throws IOException
{
return client.request(this);
}
/**
* Implementing classes should return {@code this}.
*
*
* @return request instance
*/
protected abstract T self();
/**
* Enabled http basic authentication.
*
*
* @param username username for http basic authentication
* @param password password for http basic authentication
*
* @return http request instance
*/
public T basicAuth(String username, String password)
{
String auth = Strings.nullToEmpty(username).concat(":").concat(
Strings.nullToEmpty(password));
auth = Base64.encodeToString(auth.getBytes(Charsets.ISO_8859_1));
headers.put("Authorization", "Basic ".concat(auth));
return self();
}
/**
* Enable or disabled gzip decoding. The default value is false.
*
*
* @param decodeGZip true to enable gzip decoding
*
* @return request instance
*/
public T decodeGZip(boolean decodeGZip)
{
this.decodeGZip = decodeGZip;
return self();
}
/**
* Enable or disable certificate validation of ssl certificates. The default
* value is false.
*
*
* @param disableCertificateValidation true to disable certificate validation
*
* @return request instance
*/
public T disableCertificateValidation(boolean disableCertificateValidation)
{
this.disableCertificateValidation = disableCertificateValidation;
return self();
}
/**
* Enable or disable the validation of ssl hostnames. The default value is
* false.
*
*
* @param disableHostnameValidation true to disable ssl hostname validation
*
* @return request instance
*/
public T disableHostnameValidation(boolean disableHostnameValidation)
{
this.disableHostnameValidation = disableHostnameValidation;
return self();
}
/**
* Add http headers to request.
*
*
* @param name header name
* @param values header values
*
* @return request instance
*/
public T header(String name, Object... values)
{
for (Object v : values)
{
headers.put(name, toString(v));
}
return self();
}
/**
* Add http headers to request.
*
*
* @param name header name
* @param values header values
*
* @return request instance
*/
public T headers(String name, Iterable<? extends Object> values)
{
for (Object v : values)
{
headers.put(name, toString(v));
}
return self();
}
/**
* Ignore proxy settings. The default value is false.
*
*
* @param ignoreProxySettings true to ignore proxy settings.
*
* @return request instance
*/
public T ignoreProxySettings(boolean ignoreProxySettings)
{
this.ignoreProxySettings = ignoreProxySettings;
return self();
}
/**
* Appends a query parameter to the request.
*
*
* @param name name of query parameter
* @param values query parameter values
*
* @return request instance
*/
public T queryString(String name, Object... values)
{
for (Object v : values)
{
appendQueryString(name, v);
}
return self();
}
/**
* Appends a query parameter to the request.
*
*
* @param name name of query parameter
* @param values query parameter values
*
* @return request instance
*/
public T queryStrings(String name, Iterable<? extends Object> values)
{
for (Object v : values)
{
appendQueryString(name, v);
}
return self();
}
//~--- get methods ----------------------------------------------------------
/**
* Return a map with http headers used for the request.
*
*
* @return map with http headers
*/
public Multimap<String, String> getHeaders()
{
return headers;
}
/**
* Returns the http method for the request.
*
*
* @return http method of request
*/
public String getMethod()
{
return method;
}
/**
* Returns the url for the request.
*
*
* @return url of the request
*/
public String getUrl()
{
return url;
}
/**
* Returns true if the request decodes gzip compression.
*
*
* @return true if the request decodes gzip compression
*/
public boolean isDecodeGZip()
{
return decodeGZip;
}
/**
* Returns true if the verification of ssl certificates is disabled.
*
*
* @return true if certificate verification is disabled
*/
public boolean isDisableCertificateValidation()
{
return disableCertificateValidation;
}
/**
* Returns true if the ssl hostname validation is disabled.
*
*
* @return true if the ssl hostname validation is disabled
*/
public boolean isDisableHostnameValidation()
{
return disableHostnameValidation;
}
/**
* Returns true if the proxy settings are ignored.
*
*
* @return true if the proxy settings are ignored
*/
public boolean isIgnoreProxySettings()
{
return ignoreProxySettings;
}
//~--- methods --------------------------------------------------------------
/**
* Returns the value url encoded.
*
*
* @param value value to encode
*
* @return encoded value
*/
protected String encoded(Object value)
{
return HttpUtil.encode(Strings.nullToEmpty(toString(value)));
}
/**
* Returns string representation of the given object or {@code null}, if the
* object is {@code null}.
*
*
* @param object object
*
* @return string representation or {@code null}
*/
protected String toString(Object object)
{
return (object != null)
? object.toString()
: null;
}
private void appendQueryString(String name, Object value)
{
StringBuilder buffer = new StringBuilder();
if (url.contains("?"))
{
buffer.append("&");
}
else
{
buffer.append("?");
}
buffer.append(encoded(name)).append("=").append(encoded(value));
url = url.concat(buffer.toString());
}
//~--- fields ---------------------------------------------------------------
/** http client */
protected final AdvancedHttpClient client;
/** http header */
private final Multimap<String, String> headers = LinkedHashMultimap.create();
/** http method */
private final String method;
/** ignore proxy settings */
private boolean ignoreProxySettings = false;
/** disable ssl hostname validation */
private boolean disableHostnameValidation = false;
/** disable ssl certificate validation */
private boolean disableCertificateValidation = false;
/** decode gzip */
private boolean decodeGZip = false;
/** url of request */
private String url;
}

View File

@@ -0,0 +1,97 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteSource;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
/**
* {@link ByteSource} content for {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class ByteSourceContent implements Content
{
/**
* Constructs a new {@link ByteSourceContent}.
*
*
* @param byteSource byte source
*/
public ByteSourceContent(ByteSource byteSource)
{
this.byteSource = byteSource;
}
//~--- methods --------------------------------------------------------------
/**
* Sets the content length for the request.
*
*
* @param request http request
*
* @throws IOException
*/
@Override
public void prepare(AdvancedHttpRequestWithBody request) throws IOException
{
request.contentLength(byteSource.size());
}
/**
* Copies the content of the byte source to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
@Override
public void process(OutputStream output) throws IOException
{
byteSource.copyTo(output);
}
//~--- fields ---------------------------------------------------------------
/** byte source */
private final ByteSource byteSource;
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
/**
* Content of a {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public interface Content
{
/**
* Prepares the {@link AdvancedHttpRequestWithBody} for the request content.
* Implementations can set the content type, content length or custom headers
* for the request.
*
*
* @param request request
*
* @throws IOException
*/
public void prepare(AdvancedHttpRequestWithBody request) throws IOException;
/**
* Copies the content to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
public void process(OutputStream output) throws IOException;
}

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.io.ByteSource;
import sonia.scm.plugin.ExtensionPoint;
/**
* Transforms {@link ByteSource} content to an object and vice versa. This class
* is an extension point, this means that plugins can define their own
* {@link ContentTransformer} implementations by implementing the interface and
* annotate the implementation with the {@link sonia.scm.plugin.ext.Extension}
* annotation.
*
* @author Sebastian Sdorra
* @since 1.46
*/
@ExtensionPoint
public interface ContentTransformer
{
/**
* Returns {@code true} if the transformer is responsible for the given
* object and content type.
*
* @param type object type
* @param contentType content type
*
* @return {@code true} if the transformer is responsible
*/
public boolean isResponsible(Class<?> type, String contentType);
/**
* Marshalls the given object into a {@link ByteSource}.
*
*
* @param object object to marshall
*
* @return string content
*/
public ByteSource marshall(Object object);
/**
* Unmarshall the {@link ByteSource} content to an object of the given type.
*
*
* @param type type of result object
* @param content content
* @param <T> type of result object
*
* @return
*/
public <T> T unmarshall(Class<T> type, ByteSource content);
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* A {@link ContentTransformerException} is thrown if an error occurs during
* content transformation by an {@link ContentTransformer}.
*
* @author Sebastian Sdorra
*
* @since 1.46
*/
public class ContentTransformerException extends RuntimeException
{
/** Field description */
private static final long serialVersionUID = 367333504151208563L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new {@link ContentTransformerException}.
*
*
* @param message exception message
*/
public ContentTransformerException(String message)
{
super(message);
}
/**
* Constructs a new {@link ContentTransformerException}.
*
*
* @param message exception message
* @param cause exception cause
*/
public ContentTransformerException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* The ContentTransformerNotFoundException is thrown, if no
* {@link ContentTransformer} could be found for the given type.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class ContentTransformerNotFoundException
extends ContentTransformerException
{
/** Field description */
private static final long serialVersionUID = 6374525163951460938L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new ContentTransformerNotFoundException.
*
*
* @param message exception message
*/
public ContentTransformerNotFoundException(String message)
{
super(message);
}
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* Content-Types.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public final class ContentType
{
/** json content type */
public static final String JSON = "application/json";
/** xml content type */
public static final String XML = "application/xml";
//~--- constructors ---------------------------------------------------------
private ContentType() {}
}

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Sets the content of the file to the request.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class FileContent implements Content
{
/**
* Constructs a new {@link FileContent}.
*
*
* @param file file
*/
public FileContent(File file)
{
this.file = file;
}
//~--- methods --------------------------------------------------------------
/**
* Sets the content length of the file as request header.
*
*
* @param request request
*/
@Override
public void prepare(AdvancedHttpRequestWithBody request)
{
request.contentLength(file.length());
}
/**
* Copies the content of the file to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
@Override
public void process(OutputStream output) throws IOException
{
InputStream stream = null;
try
{
stream = new FileInputStream(file);
ByteStreams.copy(stream, output);
}
finally
{
Closeables.close(stream, true);
}
}
//~--- fields ---------------------------------------------------------------
/** file */
private final File file;
}

View File

@@ -0,0 +1,139 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Strings;
import sonia.scm.util.HttpUtil;
/**
* The form builder is able to add form parameters to a request.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class FormContentBuilder
{
/**
* Constructs a new {@link FormContentBuilder}.
*
*
* @param request request
*/
public FormContentBuilder(AdvancedHttpRequestWithBody request)
{
this.request = request;
}
//~--- methods --------------------------------------------------------------
/**
* Build the formular content and append it to the request.
*
*
* @return request instance
*/
public AdvancedHttpRequestWithBody build()
{
request.contentType("application/x-www-form-urlencoded");
request.stringContent(builder.toString());
return request;
}
/**
* Adds a formular parameter.
*
*
* @param name parameter name
* @param values parameter values
*
* @return {@code this}
*/
public FormContentBuilder fields(String name, Iterable<? extends Object> values)
{
for (Object v : values)
{
append(name, v);
}
return this;
}
/**
* Adds a formular parameter.
*
*
* @param name parameter name
* @param values parameter values
*
* @return {@code this}
*/
public FormContentBuilder field(String name, Object... values)
{
for (Object v : values)
{
append(name, v);
}
return this;
}
private void append(String name, Object value)
{
if (!Strings.isNullOrEmpty(name))
{
if (builder.length() > 0)
{
builder.append("&");
}
builder.append(HttpUtil.encode(name)).append("=");
if (value != null)
{
builder.append(HttpUtil.encode(value.toString()));
}
}
}
//~--- fields ---------------------------------------------------------------
/** content builder */
private final StringBuilder builder = new StringBuilder();
/** request */
private final AdvancedHttpRequestWithBody request;
}

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* Http methods.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public final class HttpMethod
{
/** http delete method */
public static final String DELETE = "DELETE";
/** http get method */
public static final String GET = "GET";
/** http head method */
public static final String HEAD = "HEAD";
/** http options method */
public static final String OPTIONS = "OPTIONS";
/** http post method */
public static final String POST = "POST";
/** http put method */
public static final String PUT = "PUT";
//~--- constructors ---------------------------------------------------------
private HttpMethod() {}
}

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
/**
* Byte array content for {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class RawContent implements Content
{
/**
* Constructs a new {@link RawContent}.
*
*
* @param data data
*/
public RawContent(byte[] data)
{
this.data = data;
}
//~--- methods --------------------------------------------------------------
/**
* Sets the length of the byte array as http header.
*
*
* @param request request
*/
@Override
public void prepare(AdvancedHttpRequestWithBody request)
{
request.contentLength(data.length);
}
/**
* Writes the byte array to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
@Override
public void process(OutputStream output) throws IOException
{
output.write(data);
}
//~--- get methods ----------------------------------------------------------
/**
* Returns content data.
*
*
* @return content data
*/
@VisibleForTesting
byte[] getData()
{
return data;
}
//~--- fields ---------------------------------------------------------------
/** byte array */
private final byte[] data;
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
import java.nio.charset.Charset;
/**
* String content for {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class StringContent extends RawContent
{
/**
* Constructs a new {@link StringContent}.
*
*
* @param content content
* @param charset charset
*/
public StringContent(String content, Charset charset)
{
super(content.getBytes(charset));
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
/**
* Advanced http client.
*/
package sonia.scm.net.ahc;

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class AdvancedHttpClientTest {
@Mock(answer = Answers.CALLS_REAL_METHODS)
private AdvancedHttpClient client;
private static final String URL = "https://www.scm-manager.org";
@Test
public void testGet()
{
AdvancedHttpRequest request = client.get(URL);
assertEquals(URL, request.getUrl());
assertEquals(HttpMethod.GET, request.getMethod());
}
@Test
public void testDelete()
{
AdvancedHttpRequestWithBody request = client.delete(URL);
assertEquals(URL, request.getUrl());
assertEquals(HttpMethod.DELETE, request.getMethod());
}
@Test
public void testPut()
{
AdvancedHttpRequestWithBody request = client.put(URL);
assertEquals(URL, request.getUrl());
assertEquals(HttpMethod.PUT, request.getMethod());
}
@Test
public void testPost()
{
AdvancedHttpRequestWithBody request = client.post(URL);
assertEquals(URL, request.getUrl());
assertEquals(HttpMethod.POST, request.getMethod());
}
@Test
public void testOptions()
{
AdvancedHttpRequestWithBody request = client.options(URL);
assertEquals(URL, request.getUrl());
assertEquals(HttpMethod.OPTIONS, request.getMethod());
}
@Test
public void testHead()
{
AdvancedHttpRequest request = client.head(URL);
assertEquals(URL, request.getUrl());
assertEquals(HttpMethod.HEAD, request.getMethod());
}
@Test
public void testMethod()
{
AdvancedHttpRequestWithBody request = client.method("PROPFIND", URL);
assertEquals(URL, request.getUrl());
assertEquals("PROPFIND", request.getMethod());
}
}

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class AdvancedHttpRequestTest {
@Mock
private AdvancedHttpClient ahc;
@Test
public void testSelf()
{
AdvancedHttpRequest ahr = new AdvancedHttpRequest(ahc, HttpMethod.GET, "https://www.scm-manager.org");
assertEquals(AdvancedHttpRequest.class, ahr.self().getClass());
}
}

View File

@@ -0,0 +1,169 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.base.Charsets;
import com.google.common.io.ByteSource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class AdvancedHttpRequestWithBodyTest {
@Mock
private AdvancedHttpClient ahc;
@Mock
private ContentTransformer transformer;
private AdvancedHttpRequestWithBody request;
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@Before
public void before(){
request = new AdvancedHttpRequestWithBody(ahc, HttpMethod.PUT, "https://www.scm-manager.org");
}
@Test
public void testContentLength()
{
request.contentLength(12l);
assertEquals("12", request.getHeaders().get("Content-Length").iterator().next());
}
@Test
public void testContentType(){
request.contentType("text/plain");
assertEquals("text/plain", request.getHeaders().get("Content-Type").iterator().next());
}
@Test
public void testFileContent() throws IOException{
File file = tempFolder.newFile();
request.fileContent(file);
assertThat(request.getContent(), instanceOf(FileContent.class));
}
@Test
public void testRawContent() throws IOException {
request.rawContent("test".getBytes(Charsets.UTF_8));
assertThat(request.getContent(), instanceOf(RawContent.class));
}
@Test
public void testRawContentWithByteSource() throws IOException {
ByteSource bs = ByteSource.wrap("test".getBytes(Charsets.UTF_8));
request.rawContent(bs);
assertThat(request.getContent(), instanceOf(ByteSourceContent.class));
}
@Test
public void testFormContent(){
FormContentBuilder builder = request.formContent();
assertNotNull(builder);
builder.build();
assertThat(request.getContent(), instanceOf(StringContent.class));
}
@Test
public void testStringContent(){
request.stringContent("test");
assertThat(request.getContent(), instanceOf(StringContent.class));
}
@Test
public void testStringContentWithCharset(){
request.stringContent("test", Charsets.UTF_8);
assertThat(request.getContent(), instanceOf(StringContent.class));
}
@Test
public void testXmlContent() throws IOException{
when(ahc.createTransformer(String.class, ContentType.XML)).thenReturn(transformer);
when(transformer.marshall("<root />")).thenReturn(ByteSource.wrap("<root></root>".getBytes(Charsets.UTF_8)));
Content content = request.xmlContent("<root />").getContent();
assertThat(content, instanceOf(ByteSourceContent.class));
ByteSourceContent bsc = (ByteSourceContent) content;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bsc.process(baos);
assertEquals("<root></root>", baos.toString("UTF-8"));
}
@Test
public void testJsonContent() throws IOException{
when(ahc.createTransformer(String.class, ContentType.JSON)).thenReturn(transformer);
when(transformer.marshall("{}")).thenReturn(ByteSource.wrap("{'root': {}}".getBytes(Charsets.UTF_8)));
Content content = request.jsonContent("{}").getContent();
assertThat(content, instanceOf(ByteSourceContent.class));
ByteSourceContent bsc = (ByteSourceContent) content;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bsc.process(baos);
assertEquals("{'root': {}}", baos.toString("UTF-8"));
}
@Test
public void testTransformedContent() throws IOException{
when(ahc.createTransformer(String.class, "text/plain")).thenReturn(transformer);
when(transformer.marshall("hello")).thenReturn(ByteSource.wrap("hello world".getBytes(Charsets.UTF_8)));
Content content = request.transformedContent("text/plain", "hello").getContent();
assertThat(content, instanceOf(ByteSourceContent.class));
ByteSourceContent bsc = (ByteSourceContent) content;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bsc.process(baos);
assertEquals("hello world", baos.toString("UTF-8"));
}
@Test
public void testSelf()
{
assertEquals(AdvancedHttpRequestWithBody.class, request.self().getClass());
}
}

View File

@@ -0,0 +1,214 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.base.Charsets;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import java.io.IOException;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class AdvancedHttpResponseTest {
@Mock(answer = Answers.CALLS_REAL_METHODS)
private AdvancedHttpResponse response;
@Mock
private ContentTransformer transformer;
@Test
public void testContent() throws IOException
{
ByteSource bs = ByteSource.wrap("test123".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
byte[] data = response.content();
assertEquals("test123", new String(data, Charsets.UTF_8));
}
@Test
public void testContentWithoutByteSource() throws IOException
{
assertNull(response.content());
}
@Test
public void testContentAsString() throws IOException
{
ByteSource bs = ByteSource.wrap("123test".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
assertEquals("123test", response.contentAsString());
}
@Test
public void testContentAsStingWithoutByteSource() throws IOException
{
assertNull(response.contentAsString());
}
@Test
public void testContentAsReader() throws IOException
{
ByteSource bs = ByteSource.wrap("abc123".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
assertEquals("abc123", CharStreams.toString(response.contentAsReader()));
}
@Test
public void testContentAsReaderWithoutByteSource() throws IOException
{
assertNull(response.contentAsReader());
}
@Test
public void testContentAsStream() throws IOException
{
ByteSource bs = ByteSource.wrap("cde456".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
byte[] data = ByteStreams.toByteArray(response.contentAsStream());
assertEquals("cde456", new String(data, Charsets.UTF_8));
}
@Test
public void testContentAsStreamWithoutByteSource() throws IOException
{
assertNull(response.contentAsStream());
}
@Test
public void testContentFromJson() throws IOException{
ByteSource bs = ByteSource.wrap("{}".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
when(response.createTransformer(String.class, ContentType.JSON)).thenReturn(transformer);
when(transformer.unmarshall(String.class, bs)).thenReturn("{root: null}");
String c = response.contentFromJson(String.class);
assertEquals("{root: null}", c);
}
@Test
public void testContentFromXml() throws IOException{
ByteSource bs = ByteSource.wrap("<root />".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
when(response.createTransformer(String.class, ContentType.XML)).thenReturn(transformer);
when(transformer.unmarshall(String.class, bs)).thenReturn("<root></root>");
String c = response.contentFromXml(String.class);
assertEquals("<root></root>", c);
}
@Test(expected = ContentTransformerException.class)
public void testContentTransformedWithoutHeader() throws IOException{
Multimap<String,String> map = LinkedHashMultimap.create();
when(response.getHeaders()).thenReturn(map);
response.contentTransformed(String.class);
}
@Test
public void testContentTransformedFromHeader() throws IOException{
Multimap<String,String> map = LinkedHashMultimap.create();
map.put("Content-Type", "text/plain");
when(response.getHeaders()).thenReturn(map);
when(response.createTransformer(String.class, "text/plain")).thenReturn(
transformer);
ByteSource bs = ByteSource.wrap("hello".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
when(transformer.unmarshall(String.class, bs)).thenReturn("hello world");
String v = response.contentTransformed(String.class);
assertEquals("hello world", v);
}
@Test
public void testContentTransformed() throws IOException{
when(response.createTransformer(String.class, "text/plain")).thenReturn(
transformer);
ByteSource bs = ByteSource.wrap("hello".getBytes(Charsets.UTF_8));
when(response.contentAsByteSource()).thenReturn(bs);
when(transformer.unmarshall(String.class, bs)).thenReturn("hello world");
String v = response.contentTransformed(String.class, "text/plain");
assertEquals("hello world", v);
}
@Test
public void testContentTransformedWithoutByteSource() throws IOException{
assertNull(response.contentTransformed(String.class, "text/plain"));
}
@Test
public void testGetFirstHeader() throws IOException
{
Multimap<String,String> mm = LinkedHashMultimap.create();
mm.put("Test", "One");
mm.put("Test-2", "One");
mm.put("Test-2", "Two");
when(response.getHeaders()).thenReturn(mm);
assertEquals("One", response.getFirstHeader("Test"));
assertEquals("One", response.getFirstHeader("Test-2"));
assertNull(response.getFirstHeader("Test-3"));
}
@Test
public void testIsSuccessful() throws IOException
{
// successful
when(response.getStatus()).thenReturn(200);
assertTrue(response.isSuccessful());
when(response.getStatus()).thenReturn(201);
assertTrue(response.isSuccessful());
when(response.getStatus()).thenReturn(204);
assertTrue(response.isSuccessful());
when(response.getStatus()).thenReturn(301);
assertTrue(response.isSuccessful());
// not successful
when(response.getStatus()).thenReturn(400);
assertFalse(response.isSuccessful());
when(response.getStatus()).thenReturn(404);
assertFalse(response.isSuccessful());
when(response.getStatus()).thenReturn(500);
assertFalse(response.isSuccessful());
when(response.getStatus()).thenReturn(199);
assertFalse(response.isSuccessful());
}
}

View File

@@ -0,0 +1,142 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import java.io.IOException;
import java.util.Collection;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class BaseHttpRequestTest {
@Mock
private AdvancedHttpClient ahc;
private BaseHttpRequest<AdvancedHttpRequest> request;
@Before
public void before(){
request = new AdvancedHttpRequest(ahc, HttpMethod.GET, "https://www.scm-manager.org");
}
@Test
public void testBasicAuth()
{
request.basicAuth("tricia", "mcmillian123");
Multimap<String,String> headers = request.getHeaders();
assertEquals("Basic dHJpY2lhOm1jbWlsbGlhbjEyMw==", headers.get("Authorization").iterator().next());
}
@Test
public void testQueryString(){
request.queryString("a", "b");
assertEquals("https://www.scm-manager.org?a=b", request.getUrl());
}
@Test
public void testQueryStringMultiple(){
request.queryString("a", "b");
request.queryString("c", "d", "e");
assertEquals("https://www.scm-manager.org?a=b&c=d&c=e", request.getUrl());
}
@Test
public void testQueryStringEncoded(){
request.queryString("a", "äüö");
assertEquals("https://www.scm-manager.org?a=%C3%A4%C3%BC%C3%B6", request.getUrl());
}
@Test
public void testQueryStrings(){
Iterable<? extends Object> i1 = Lists.newArrayList("b");
Iterable<? extends Object> i2 = Lists.newArrayList("d", "e");
request.queryStrings("a", i1);
request.queryStrings("c", i2);
assertEquals("https://www.scm-manager.org?a=b&c=d&c=e", request.getUrl());
}
@Test
public void testQuerqStringNullValue(){
request.queryString("a", null, "b");
assertEquals("https://www.scm-manager.org?a=&a=b", request.getUrl());
}
@Test
public void testHeader(){
request.header("a", "b");
assertEquals("b", request.getHeaders().get("a").iterator().next());
}
@Test
public void testHeaderMultiple(){
request.header("a", "b", "c", "d");
Collection<String> values = request.getHeaders().get("a");
assertThat(values, contains("b", "c", "d"));
}
@Test
public void testRequest() throws IOException{
request.request();
verify(ahc).request(request);
}
@Test
public void testBuilderMethods(){
Iterable<? extends Object> i1 = Lists.newArrayList("b");
assertThat(request.decodeGZip(true), instanceOf(AdvancedHttpRequest.class));
assertTrue(request.isDecodeGZip());
assertThat(request.disableCertificateValidation(true), instanceOf(AdvancedHttpRequest.class));
assertTrue(request.isDisableCertificateValidation());
assertThat(request.disableHostnameValidation(true), instanceOf(AdvancedHttpRequest.class));
assertTrue(request.isDisableHostnameValidation());
assertThat(request.ignoreProxySettings(true), instanceOf(AdvancedHttpRequest.class));
assertTrue(request.isIgnoreProxySettings());
assertThat(request.header("a", "b"), instanceOf(AdvancedHttpRequest.class));
assertThat(request.headers("a", i1), instanceOf(AdvancedHttpRequest.class));
assertThat(request.queryString("a", "b"), instanceOf(AdvancedHttpRequest.class));
assertThat(request.queryStrings("a", i1), instanceOf(AdvancedHttpRequest.class));
}
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.base.Charsets;
import com.google.common.io.ByteSource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class ByteSourceContentTest {
@Mock
private AdvancedHttpRequestWithBody request;
@Test
public void testPrepareRequest() throws IOException
{
ByteSource source = ByteSource.wrap("abc".getBytes(Charsets.UTF_8));
ByteSourceContent content = new ByteSourceContent(source);
content.prepare(request);
verify(request).contentLength(3l);
}
@Test
public void testProcess() throws IOException{
ByteSource source = ByteSource.wrap("abc".getBytes(Charsets.UTF_8));
ByteSourceContent content = new ByteSourceContent(source);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
content.process(baos);
assertEquals("abc", baos.toString("UTF-8"));
}
}

View File

@@ -0,0 +1,116 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class FileContentTest
{
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testPrepareRequest() throws IOException
{
FileContent content = create("abc");
content.prepare(request);
verify(request).contentLength(3l);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testProcess() throws IOException
{
FileContent content = create("abc");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
content.process(baos);
assertEquals("abc", baos.toString("UTF-8"));
}
private FileContent create(String value) throws IOException
{
File file = temp.newFile();
Files.write("abc", file, Charsets.UTF_8);
return new FileContent(file);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@Rule
public TemporaryFolder temp = new TemporaryFolder();
/** Field description */
@Mock
private AdvancedHttpRequestWithBody request;
}

View File

@@ -0,0 +1,95 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.collect.Lists;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class FormContentBuilderTest {
@Mock
private AdvancedHttpRequestWithBody request;
@InjectMocks
private FormContentBuilder builder;
@Test
public void testFieldEncoding()
{
builder.field("a", "ü", "ä", "ö").build();
assertContent("a=%C3%BC&a=%C3%A4&a=%C3%B6");
}
@Test
public void testBuild()
{
builder.field("a", "b").build();
assertContent("a=b");
verify(request).contentType("application/x-www-form-urlencoded");
}
@Test
public void testFieldWithArray()
{
builder.field("a", "b").field("c", "d", "e").build();
assertContent("a=b&c=d&c=e");
}
@Test
public void testFieldWithIterable()
{
Iterable<? extends Object> i1 = Lists.newArrayList("b");
builder.fields("a", i1)
.fields("c", Lists.newArrayList("d", "e"))
.build();
assertContent("a=b&c=d&c=e");
}
private void assertContent(String content){
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(request).stringContent(captor.capture());
assertEquals(content, captor.getValue());
}
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.base.Charsets;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class RawContentTest {
@Mock
private AdvancedHttpRequestWithBody request;
@Test
public void testPrepareRequest()
{
RawContent raw = new RawContent("abc".getBytes(Charsets.UTF_8));
raw.prepare(request);
verify(request).contentLength(3);
}
@Test
public void testProcess() throws IOException
{
RawContent raw = new RawContent("abc".getBytes(Charsets.UTF_8));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
raw.process(baos);
assertEquals("abc", baos.toString("UTF-8"));
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.base.Charsets;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author Sebastian Sdorra
*/
public class StringContentTest {
@Test
public void testStringContent()
{
StringContent sc = new StringContent("abc", Charsets.UTF_8);
assertEquals("abc", new String(sc.getData()));
}
@Test
public void testStringContentWithCharset()
{
StringContent sc = new StringContent("üäö", Charsets.ISO_8859_1);
assertEquals("üäö", new String(sc.getData(), Charsets.ISO_8859_1));
}
}

View File

@@ -43,7 +43,7 @@ import sonia.scm.installer.HgInstallerFactory;
import sonia.scm.installer.HgPackage;
import sonia.scm.installer.HgPackageReader;
import sonia.scm.installer.HgPackages;
import sonia.scm.net.HttpClient;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
@@ -89,8 +89,8 @@ public class HgConfigResource
* @param pkgReader
*/
@Inject
public HgConfigResource(HttpClient client, HgRepositoryHandler handler,
HgPackageReader pkgReader)
public HgConfigResource(AdvancedHttpClient client,
HgRepositoryHandler handler, HgPackageReader pkgReader)
{
this.client = client;
this.handler = handler;
@@ -158,7 +158,7 @@ public class HgConfigResource
if (pkg != null)
{
if (HgInstallerFactory.createInstaller().installPackage(client, handler,
SCMContext.getContext().getBaseDirectory(), pkg))
SCMContext.getContext().getBaseDirectory(), pkg))
{
response = Response.noContent().build();
}
@@ -262,7 +262,7 @@ public class HgConfigResource
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response setConfig(@Context UriInfo uriInfo, HgConfig config)
throws IOException
throws IOException
{
handler.setConfig(config);
handler.storeConfig();
@@ -338,7 +338,7 @@ public class HgConfigResource
//~--- fields ---------------------------------------------------------------
/** Field description */
private HttpClient client;
private AdvancedHttpClient client;
/** Field description */
private HgRepositoryHandler handler;

View File

@@ -35,7 +35,6 @@ package sonia.scm.installer;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.net.HttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.util.IOUtil;
@@ -44,6 +43,7 @@ import sonia.scm.util.IOUtil;
import java.io.File;
import java.io.IOException;
import sonia.scm.net.ahc.AdvancedHttpClient;
/**
*
@@ -93,7 +93,7 @@ public abstract class AbstractHgInstaller implements HgInstaller
* @return
*/
@Override
public boolean installPackage(HttpClient client, HgRepositoryHandler handler,
public boolean installPackage(AdvancedHttpClient client, HgRepositoryHandler handler,
File baseDirectory, HgPackage pkg)
{
return new HgPackageInstaller(client, handler, baseDirectory,

View File

@@ -35,7 +35,7 @@ package sonia.scm.installer;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.net.HttpClient;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
@@ -78,8 +78,8 @@ public interface HgInstaller
*
* @return
*/
public boolean installPackage(HttpClient client, HgRepositoryHandler handler,
File baseDirectory, HgPackage pkg);
public boolean installPackage(AdvancedHttpClient client,
HgRepositoryHandler handler, File baseDirectory, HgPackage pkg);
/**
* Method description

View File

@@ -40,10 +40,10 @@ import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext;
import sonia.scm.io.ZipUnArchiver;
import sonia.scm.net.HttpClient;
import sonia.scm.repository.HgWindowsPackageFix;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.HgWindowsPackageFix;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
@@ -80,8 +80,8 @@ public class HgPackageInstaller implements Runnable
* @param baseDirectory
* @param pkg
*/
public HgPackageInstaller(HttpClient client, HgRepositoryHandler handler,
File baseDirectory, HgPackage pkg)
public HgPackageInstaller(AdvancedHttpClient client,
HgRepositoryHandler handler, File baseDirectory, HgPackage pkg)
{
this.client = client;
this.handler = handler;
@@ -155,7 +155,7 @@ public class HgPackageInstaller implements Runnable
}
// TODO error handling
input = client.get(pkg.getUrl()).getContent();
input = client.get(pkg.getUrl()).request().contentAsStream();
output = new FileOutputStream(file);
IOUtil.copy(input, output);
}
@@ -265,7 +265,7 @@ public class HgPackageInstaller implements Runnable
private File baseDirectory;
/** Field description */
private HttpClient client;
private AdvancedHttpClient client;
/** Field description */
private HgRepositoryHandler handler;

View File

@@ -36,7 +36,6 @@ package sonia.scm.installer;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,22 +43,17 @@ import org.slf4j.LoggerFactory;
import sonia.scm.PlatformType;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.net.HttpClient;
import sonia.scm.net.HttpResponse;
import sonia.scm.util.IOUtil;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.util.SystemUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXB;
/**
*
* @author Sebastian Sdorra
@@ -85,14 +79,14 @@ public class HgPackageReader
*
*
* @param cacheManager
* @param httpClientProvider
* @param httpClient
*/
@Inject
public HgPackageReader(CacheManager cacheManager,
Provider<HttpClient> httpClientProvider)
AdvancedHttpClient httpClient)
{
cache = cacheManager.getCache(String.class, HgPackages.class, CACHENAME);
this.httpClientProvider = httpClientProvider;
this.httpClient = httpClient;
}
//~--- get methods ----------------------------------------------------------
@@ -167,7 +161,7 @@ public class HgPackageReader
if (logger.isDebugEnabled())
{
logger.debug("reject package {}, because of wrong platform {}",
pkg.getId(), pkg.getPlatform());
pkg.getId(), pkg.getPlatform());
}
add = false;
@@ -181,7 +175,7 @@ public class HgPackageReader
if (logger.isDebugEnabled())
{
logger.debug("reject package {}, because of wrong arch {}",
pkg.getId(), pkg.getArch());
pkg.getId(), pkg.getArch());
}
add = false;
@@ -218,23 +212,19 @@ public class HgPackageReader
}
HgPackages packages = null;
InputStream input = null;
try
{
HttpResponse response = httpClientProvider.get().get(PACKAGEURL);
input = response.getContent();
packages = JAXB.unmarshal(input, HgPackages.class);
//J-
packages = httpClient.get(PACKAGEURL)
.request()
.contentFromXml(HgPackages.class);
//J+
}
catch (IOException ex)
{
logger.error("could not read HgPackages from ".concat(PACKAGEURL), ex);
}
finally
{
IOUtil.close(input);
}
if (packages == null)
{
@@ -251,5 +241,5 @@ public class HgPackageReader
private Cache<String, HgPackages> cache;
/** Field description */
private Provider<HttpClient> httpClientProvider;
private AdvancedHttpClient httpClient;
}

View File

@@ -47,9 +47,6 @@ import org.slf4j.LoggerFactory;
import sonia.scm.ConfigChangedListener;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.net.HttpClient;
import sonia.scm.net.HttpRequest;
import sonia.scm.net.HttpResponse;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
@@ -60,6 +57,7 @@ import java.io.IOException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import sonia.scm.net.ahc.AdvancedHttpClient;
/**
*
@@ -86,17 +84,17 @@ public class HgHookManager implements ConfigChangedListener<ScmConfiguration>
*
* @param configuration
* @param httpServletRequestProvider
* @param httpClientProvider
* @param httpClient
*/
@Inject
public HgHookManager(ScmConfiguration configuration,
Provider<HttpServletRequest> httpServletRequestProvider,
Provider<HttpClient> httpClientProvider)
AdvancedHttpClient httpClient)
{
this.configuration = configuration;
this.configuration.addListener(this);
this.httpServletRequestProvider = httpServletRequestProvider;
this.httpClientProvider = httpClientProvider;
this.httpClient = httpClient;
}
//~--- methods --------------------------------------------------------------
@@ -359,20 +357,16 @@ public class HgHookManager implements ConfigChangedListener<ScmConfiguration>
{
url = url.concat("?ping=true");
if (logger.isTraceEnabled())
{
logger.trace("check hook url {}", url);
}
HttpRequest request = new HttpRequest(url);
request.setDisableCertificateValidation(true);
request.setDisableHostnameValidation(true);
request.setIgnoreProxySettings(true);
HttpResponse response = httpClientProvider.get().get(request);
result = response.getStatusCode() == 204;
logger.trace("check hook url {}", url);
//J-
int sc = httpClient.get(url)
.disableHostnameValidation(true)
.disableCertificateValidation(true)
.ignoreProxySettings(true)
.request()
.getStatus();
//J+
result = sc == 204;
}
catch (IOException ex)
{
@@ -397,7 +391,7 @@ public class HgHookManager implements ConfigChangedListener<ScmConfiguration>
private volatile String hookUrl;
/** Field description */
private Provider<HttpClient> httpClientProvider;
private AdvancedHttpClient httpClient;
/** Field description */
private Provider<HttpServletRequest> httpServletRequestProvider;

View File

@@ -157,6 +157,11 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.net.ahc.ContentTransformer;
import sonia.scm.net.ahc.DefaultAdvancedHttpClient;
import sonia.scm.net.ahc.JsonContentTransformer;
import sonia.scm.net.ahc.XmlContentTransformer;
import sonia.scm.web.UserAgentParser;
/**
@@ -219,7 +224,7 @@ public class ScmServletModule extends ServletModule
PATTERN_STYLESHEET, "*.json", "*.xml", "*.txt" };
/** Field description */
private static Logger logger =
private static final Logger logger =
LoggerFactory.getLogger(ScmServletModule.class);
//~--- constructors ---------------------------------------------------------
@@ -315,6 +320,13 @@ public class ScmServletModule extends ServletModule
// bind httpclient
bind(HttpClient.class, URLHttpClient.class);
// bind ahc
Multibinder<ContentTransformer> transformers =
Multibinder.newSetBinder(binder(), ContentTransformer.class);
transformers.addBinding().to(XmlContentTransformer.class);
transformers.addBinding().to(JsonContentTransformer.class);
bind(AdvancedHttpClient.class).to(DefaultAdvancedHttpClient.class);
// bind resourcemanager
if (context.getStage() == Stage.DEVELOPMENT)

View File

@@ -74,7 +74,9 @@ import sonia.scm.util.HttpUtil;
/**
*
* @author Sebastian Sdorra
* @deprecated use {@link sonia.scm.net.ahc.AdvancedHttpClient}
*/
@Deprecated
public class URLHttpClient implements HttpClient
{

View File

@@ -0,0 +1,398 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.Multimap;
import com.google.common.io.Closeables;
import com.google.inject.Inject;
import org.apache.shiro.codec.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.net.Proxies;
import sonia.scm.net.TrustAllHostnameVerifier;
import sonia.scm.net.TrustAllTrustManager;
import sonia.scm.util.HttpUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Set;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
/**
* Default implementation of the {@link AdvancedHttpClient}. The default
* implementation uses {@link HttpURLConnection}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class DefaultAdvancedHttpClient extends AdvancedHttpClient
{
/** proxy authorization header */
@VisibleForTesting
static final String HEADER_PROXY_AUTHORIZATION = "Proxy-Authorization";
/** connection timeout */
@VisibleForTesting
static final int TIMEOUT_CONNECTION = 30000;
/** read timeout */
@VisibleForTesting
static final int TIMEOUT_RAED = 1200000;
/** credential separator */
private static final String CREDENTIAL_SEPARATOR = ":";
/** basic authentication prefix */
private static final String PREFIX_BASIC_AUTHENTICATION = "Basic ";
/**
* the logger for DefaultAdvancedHttpClient
*/
private static final Logger logger =
LoggerFactory.getLogger(DefaultAdvancedHttpClient.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new {@link DefaultAdvancedHttpClient}.
*
*
* @param configuration scm-manager main configuration
* @param contentTransformers content transformer
*/
@Inject
public DefaultAdvancedHttpClient(ScmConfiguration configuration,
Set<ContentTransformer> contentTransformers)
{
this.configuration = configuration;
this.contentTransformers = contentTransformers;
}
//~--- methods --------------------------------------------------------------
/**
* Creates a new {@link HttpURLConnection} from the given {@link URL}. The
* method is visible for testing.
*
*
* @param url url
*
* @return new {@link HttpURLConnection}
*
* @throws IOException
*/
@VisibleForTesting
protected HttpURLConnection createConnection(URL url) throws IOException
{
return (HttpURLConnection) url.openConnection();
}
/**
* Creates a new proxy {@link HttpURLConnection} from the given {@link URL}
* and {@link SocketAddress}. The method is visible for testing.
*
*
* @param url url
* @param address proxy socket address
*
* @return new proxy {@link HttpURLConnection}
*
* @throws IOException
*/
@VisibleForTesting
protected HttpURLConnection createProxyConnecton(URL url,
SocketAddress address)
throws IOException
{
return (HttpURLConnection) url.openConnection(new Proxy(Proxy.Type.HTTP,
address));
}
/**
* {@inheritDoc}
*/
@Override
protected ContentTransformer createTransformer(Class<?> type, String contentType)
{
ContentTransformer responsible = null;
for (ContentTransformer transformer : contentTransformers)
{
if (transformer.isResponsible(type, contentType))
{
responsible = transformer;
break;
}
}
if (responsible == null)
{
throw new ContentTransformerNotFoundException(
"could not find content transformer for content type ".concat(
contentType));
}
return responsible;
}
/**
* Executes the given request and returns the server response.
*
*
* @param request http request
*
* @return server response
*
* @throws IOException
*/
@Override
protected AdvancedHttpResponse request(BaseHttpRequest<?> request)
throws IOException
{
HttpURLConnection connection = openConnection(request,
new URL(request.getUrl()));
applyBaseSettings(request, connection);
if (connection instanceof HttpsURLConnection)
{
applySSLSettings(request, (HttpsURLConnection) connection);
}
Content content = null;
if (request instanceof AdvancedHttpRequestWithBody)
{
AdvancedHttpRequestWithBody ahrwb = (AdvancedHttpRequestWithBody) request;
content = ahrwb.getContent();
if (content != null)
{
content.prepare(ahrwb);
}
else
{
request.header(HttpUtil.HEADER_CONTENT_LENGTH, "0");
}
}
else
{
request.header(HttpUtil.HEADER_CONTENT_LENGTH, "0");
}
applyHeaders(request, connection);
if (content != null)
{
applyContent(connection, content);
}
return new DefaultAdvancedHttpResponse(this, connection,
connection.getResponseCode(), connection.getResponseMessage());
}
private void appendProxyAuthentication(HttpURLConnection connection)
{
String username = configuration.getProxyUser();
String password = configuration.getProxyPassword();
if (!Strings.isNullOrEmpty(username) ||!Strings.isNullOrEmpty(password))
{
logger.debug("append proxy authentication header for user {}", username);
String auth = username.concat(CREDENTIAL_SEPARATOR).concat(password);
auth = Base64.encodeToString(auth.getBytes());
connection.addRequestProperty(HEADER_PROXY_AUTHORIZATION,
PREFIX_BASIC_AUTHENTICATION.concat(auth));
}
}
private void applyBaseSettings(BaseHttpRequest<?> request,
HttpURLConnection connection)
throws ProtocolException
{
connection.setRequestMethod(request.getMethod());
connection.setReadTimeout(TIMEOUT_RAED);
connection.setConnectTimeout(TIMEOUT_CONNECTION);
}
private void applyContent(HttpURLConnection connection, Content content)
throws IOException
{
connection.setDoOutput(true);
OutputStream output = null;
try
{
output = connection.getOutputStream();
content.process(output);
}
finally
{
Closeables.close(output, true);
}
}
private void applyHeaders(BaseHttpRequest<?> request,
HttpURLConnection connection)
{
Multimap<String, String> headers = request.getHeaders();
for (String key : headers.keySet())
{
for (String value : headers.get(key))
{
connection.addRequestProperty(key, value);
}
}
}
private void applySSLSettings(BaseHttpRequest<?> request,
HttpsURLConnection connection)
{
if (request.isDisableCertificateValidation())
{
logger.trace("disable certificate validation");
try
{
TrustManager[] trustAllCerts = new TrustManager[] {
new TrustAllTrustManager() };
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
connection.setSSLSocketFactory(sc.getSocketFactory());
}
catch (KeyManagementException ex)
{
logger.error("could not disable certificate validation", ex);
}
catch (NoSuchAlgorithmException ex)
{
logger.error("could not disable certificate validation", ex);
}
}
if (request.isDisableHostnameValidation())
{
logger.trace("disable hostname validation");
connection.setHostnameVerifier(new TrustAllHostnameVerifier());
}
}
private HttpURLConnection openConnection(BaseHttpRequest<?> request, URL url)
throws IOException
{
HttpURLConnection connection;
if (isProxyEnabled(request))
{
connection = openProxyConnection(request, url);
appendProxyAuthentication(connection);
}
else
{
if (request.isIgnoreProxySettings())
{
logger.trace("ignore proxy settings");
}
logger.debug("fetch {}", url.toExternalForm());
connection = createConnection(url);
}
return connection;
}
private HttpURLConnection openProxyConnection(BaseHttpRequest<?> request,
URL url)
throws IOException
{
if (logger.isDebugEnabled())
{
logger.debug("fetch '{}' using proxy {}:{}", url.toExternalForm(),
configuration.getProxyServer(), configuration.getProxyPort());
}
SocketAddress address =
new InetSocketAddress(configuration.getProxyServer(),
configuration.getProxyPort());
return createProxyConnecton(url, address);
}
//~--- get methods ----------------------------------------------------------
private boolean isProxyEnabled(BaseHttpRequest<?> request)
{
return !request.isIgnoreProxySettings()
&& Proxies.isEnabled(configuration, request.getUrl());
}
//~--- fields ---------------------------------------------------------------
/** scm-manager main configuration */
private final ScmConfiguration configuration;
/** set of content transformers */
private final Set<ContentTransformer> contentTransformers;
}

View File

@@ -0,0 +1,226 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map.Entry;
/**
* Http server response object of {@link DefaultAdvancedHttpClient}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class DefaultAdvancedHttpResponse extends AdvancedHttpResponse
{
/**
* Constructs a new {@link DefaultAdvancedHttpResponse}.
*
* @param client ahc
* @param connection http connection
* @param status response status code
* @param statusText response status text
*/
DefaultAdvancedHttpResponse(DefaultAdvancedHttpClient client,
HttpURLConnection connection, int status, String statusText)
{
this.client = client;
this.connection = connection;
this.status = status;
this.statusText = statusText;
}
//~--- methods --------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public ByteSource contentAsByteSource() throws IOException
{
return new URLConnectionByteSource(connection);
}
//~--- get methods ----------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public Multimap<String, String> getHeaders()
{
if (headers == null)
{
headers = LinkedHashMultimap.create();
for (Entry<String, List<String>> e :
connection.getHeaderFields().entrySet())
{
headers.putAll(e.getKey(), e.getValue());
}
}
return headers;
}
/**
* {@inheritDoc}
*/
@Override
public int getStatus()
{
return status;
}
/**
* {@inheritDoc}
*/
@Override
public String getStatusText()
{
return statusText;
}
//~--- methods --------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
protected ContentTransformer createTransformer(Class<?> type,
String contentType)
{
return client.createTransformer(type, contentType);
}
//~--- inner classes --------------------------------------------------------
/**
* {@link ByteSource} implementation of a http connection.
*/
private static class URLConnectionByteSource extends ByteSource
{
/**
* the logger for URLConnectionByteSource
*/
private static final Logger logger =
LoggerFactory.getLogger(URLConnectionByteSource.class);
//~--- constructors -------------------------------------------------------
/**
* Constructs a new {@link URLConnectionByteSource}.
*
*
* @param connection http connection
*/
private URLConnectionByteSource(HttpURLConnection connection)
{
this.connection = connection;
}
//~--- methods ------------------------------------------------------------
/**
* Opens the input stream of http connection, if an error occurs during
* opening the method will return the error stream instead.
*
*
* @return input or error stream of http connection
*
* @throws IOException
*/
@Override
public InputStream openStream() throws IOException
{
InputStream stream;
try
{
stream = connection.getInputStream();
}
catch (IOException ex)
{
if (logger.isDebugEnabled())
{
logger.debug(
"could not open input stream, open error stream instead", ex);
}
stream = connection.getErrorStream();
}
return stream;
}
//~--- fields -------------------------------------------------------------
/** http connection */
private final HttpURLConnection connection;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final DefaultAdvancedHttpClient client;
/** http connection */
private final HttpURLConnection connection;
/** server response status */
private final int status;
/** server response text */
private final String statusText;
/** http headers */
private Multimap<String, String> headers;
}

View File

@@ -0,0 +1,149 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteSource;
import org.codehaus.jackson.map.ObjectMapper;
import sonia.scm.plugin.ext.Extension;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
/**
* {@link ContentTransformer} for json. The {@link JsonContentTransformer} uses
* jacksons {@link ObjectMapper} to marshalling/unmarshalling.
*
* @author Sebastian Sdorra
* @since 1.46
*/
@Extension
public class JsonContentTransformer implements ContentTransformer
{
public JsonContentTransformer()
{
this.mapper = new ObjectMapper();
AnnotationIntrospector jackson = new JacksonAnnotationIntrospector();
AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector();
AnnotationIntrospector pair = new AnnotationIntrospector.Pair(jackson, jaxb);
this.mapper.setAnnotationIntrospector(pair);
}
/**
* {@inheritDoc}
*/
@Override
public ByteSource marshall(Object object)
{
ByteSource source = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
mapper.writeValue(baos, object);
source = ByteSource.wrap(baos.toByteArray());
}
catch (IOException ex)
{
throw new ContentTransformerException("could not marshall object", ex);
}
return source;
}
/**
* {@inheritDoc}
*/
@Override
public <T> T unmarshall(Class<T> type, ByteSource content)
{
T object = null;
InputStream stream = null;
try
{
stream = content.openBufferedStream();
object = mapper.readValue(stream, type);
}
catch (IOException ex)
{
throw new ContentTransformerException("could not unmarshall content", ex);
}
finally
{
IOUtil.close(stream);
}
return object;
}
//~--- get methods ----------------------------------------------------------
/**
* Returns {@code true}, if the content type is compatible with
* application/json.
*
*
* @param type object type
* @param contentType content type
*
* @return {@code true}, if the content type is compatible with
* application/json
*/
@Override
public boolean isResponsible(Class<?> type, String contentType)
{
return MediaType.valueOf(contentType).isCompatible(
MediaType.APPLICATION_JSON_TYPE);
}
//~--- fields ---------------------------------------------------------------
/** object mapper */
private final ObjectMapper mapper;
}

View File

@@ -0,0 +1,134 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteSource;
import sonia.scm.plugin.ext.Extension;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.DataBindingException;
import javax.xml.bind.JAXB;
/**
* {@link ContentTransformer} for xml. The {@link XmlContentTransformer} uses
* jaxb to marshalling/unmarshalling.
*
* @author Sebastian Sdorra
* @since 1.46
*/
@Extension
public class XmlContentTransformer implements ContentTransformer
{
/**
* {@inheritDoc}
*/
@Override
public ByteSource marshall(Object object)
{
ByteSource source = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
JAXB.marshal(object, baos);
source = ByteSource.wrap(baos.toByteArray());
}
catch (DataBindingException ex)
{
throw new ContentTransformerException("could not marshall object", ex);
}
return source;
}
/**
* {@inheritDoc}
*/
@Override
public <T> T unmarshall(Class<T> type, ByteSource content)
{
T object = null;
InputStream stream = null;
try
{
stream = content.openBufferedStream();
object = JAXB.unmarshal(stream, type);
}
catch (IOException ex)
{
throw new ContentTransformerException("could not unmarshall content", ex);
}
catch (DataBindingException ex)
{
throw new ContentTransformerException("could not unmarshall content", ex);
}
finally
{
IOUtil.close(stream);
}
return object;
}
//~--- get methods ----------------------------------------------------------
/**
* Returns {@code true}, if the content type is compatible with
* application/xml.
*
*
* @param type object type
* @param contentType content type
*
* @return {@code true}, if the content type is compatible with
* application/xml
*/
@Override
public boolean isResponsible(Class<?> type, String contentType)
{
return MediaType.valueOf(contentType).isCompatible(
MediaType.APPLICATION_XML_TYPE);
}
}

View File

@@ -40,21 +40,18 @@ import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ConfigChangedListener;
import sonia.scm.ConfigurationException;
import sonia.scm.SCMContext;
import sonia.scm.SCMContextProvider;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.io.ZipUnArchiver;
import sonia.scm.net.HttpClient;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.IOUtil;
import sonia.scm.util.SecurityUtil;
@@ -79,9 +76,7 @@ import java.util.Map;
import java.util.Set;
import javax.xml.bind.JAXB;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import sonia.scm.net.ahc.AdvancedHttpClient;
/**
*
@@ -122,18 +117,18 @@ public class DefaultPluginManager
* @param configuration
* @param pluginLoader
* @param cacheManager
* @param clientProvider
* @param httpClient
*/
@Inject
public DefaultPluginManager(SCMContextProvider context,
ScmConfiguration configuration, PluginLoader pluginLoader,
CacheManager cacheManager, Provider<HttpClient> clientProvider)
CacheManager cacheManager, AdvancedHttpClient httpClient)
{
this.context = context;
this.configuration = configuration;
this.cache = cacheManager.getCache(String.class, PluginCenter.class,
CACHE_NAME);
this.clientProvider = clientProvider;
this.httpClient = httpClient;
installedPlugins = new HashMap<String, Plugin>();
for (Plugin plugin : pluginLoader.getInstalledPlugins())
@@ -146,16 +141,6 @@ public class DefaultPluginManager
}
}
try
{
unmarshaller =
JAXBContext.newInstance(PluginCenter.class).createUnmarshaller();
}
catch (JAXBException ex)
{
throw new ConfigurationException(ex);
}
File file = findAdvancedConfiguration();
if (file.exists())
@@ -654,21 +639,9 @@ public class DefaultPluginManager
if (Util.isNotEmpty(pluginUrl))
{
InputStream input = null;
try
{
input = clientProvider.get().get(pluginUrl).getContent();
/*
* TODO: add gzip support
*
* if (gzip)
* {
* input = new GZIPInputStream(input);
* }
*/
center = (PluginCenter) unmarshaller.unmarshal(input);
center = httpClient.get(pluginUrl).request().contentFromXml(PluginCenter.class);
preparePlugins(center);
cache.put(PluginCenter.class.getName(), center);
@@ -690,10 +663,6 @@ public class DefaultPluginManager
{
logger.error("could not load plugins from plugin center", ex);
}
finally
{
IOUtil.close(input);
}
}
if (center == null)
@@ -794,7 +763,7 @@ public class DefaultPluginManager
private Cache<String, PluginCenter> cache;
/** Field description */
private Provider<HttpClient> clientProvider;
private AdvancedHttpClient httpClient;
/** Field description */
private ScmConfiguration configuration;
@@ -807,7 +776,4 @@ public class DefaultPluginManager
/** Field description */
private AetherPluginHandler pluginHandler;
/** Field description */
private Unmarshaller unmarshaller;
}

View File

@@ -0,0 +1,375 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.net.TrustAllHostnameVerifier;
import sonia.scm.util.HttpUtil;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.SocketAddress;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultAdvancedHttpClientTest
{
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyBaseSettings() throws IOException
{
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").request();
verify(connection).setRequestMethod(HttpMethod.GET);
verify(connection).setReadTimeout(DefaultAdvancedHttpClient.TIMEOUT_RAED);
verify(connection).setConnectTimeout(
DefaultAdvancedHttpClient.TIMEOUT_CONNECTION);
verify(connection).addRequestProperty(HttpUtil.HEADER_CONTENT_LENGTH, "0");
}
@Test(expected = ContentTransformerNotFoundException.class)
public void testContentTransformerNotFound(){
client.createTransformer(String.class, "text/plain");
}
@Test
public void testContentTransformer(){
ContentTransformer transformer = mock(ContentTransformer.class);
when(transformer.isResponsible(String.class, "text/plain")).thenReturn(Boolean.TRUE);
transformers.add(transformer);
ContentTransformer t = client.createTransformer(String.class, "text/plain");
assertSame(transformer, t);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyContent() throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
when(connection.getOutputStream()).thenReturn(baos);
AdvancedHttpRequestWithBody request =
new AdvancedHttpRequestWithBody(client, HttpMethod.PUT,
"https://www.scm-manager.org");
request.stringContent("test").request();
verify(connection).setDoOutput(true);
verify(connection).addRequestProperty(HttpUtil.HEADER_CONTENT_LENGTH, "4");
assertEquals("test", baos.toString("UTF-8"));
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyHeaders() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.POST,
"http://www.scm-manager.org");
request.header("Header-One", "One").header("Header-Two", "Two").request();
verify(connection).setRequestMethod(HttpMethod.POST);
verify(connection).addRequestProperty("Header-One", "One");
verify(connection).addRequestProperty("Header-Two", "Two");
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyMultipleHeaders() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.POST,
"http://www.scm-manager.org");
request.header("Header-One", "One").header("Header-One", "Two").request();
verify(connection).setRequestMethod(HttpMethod.POST);
verify(connection).addRequestProperty("Header-One", "One");
verify(connection).addRequestProperty("Header-One", "Two");
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testBodyRequestWithoutContent() throws IOException
{
AdvancedHttpRequestWithBody request =
new AdvancedHttpRequestWithBody(client, HttpMethod.PUT,
"https://www.scm-manager.org");
request.request();
verify(connection).addRequestProperty(HttpUtil.HEADER_CONTENT_LENGTH, "0");
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testDisableCertificateValidation() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.GET,
"https://www.scm-manager.org");
request.disableCertificateValidation(true).request();
verify(connection).setSSLSocketFactory(any(SSLSocketFactory.class));
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testDisableHostnameValidation() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.GET,
"https://www.scm-manager.org");
request.disableHostnameValidation(true).request();
verify(connection).setHostnameVerifier(any(TrustAllHostnameVerifier.class));
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testIgnoreProxy() throws IOException
{
configuration.setProxyServer("proxy.scm-manager.org");
configuration.setProxyPort(8090);
configuration.setEnableProxy(true);
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").ignoreProxySettings(true).request();
assertFalse(client.proxyConnection);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testProxyConnection() throws IOException
{
configuration.setProxyServer("proxy.scm-manager.org");
configuration.setProxyPort(8090);
configuration.setEnableProxy(true);
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").request();
assertTrue(client.proxyConnection);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testProxyWithAuthentication() throws IOException
{
configuration.setProxyServer("proxy.scm-manager.org");
configuration.setProxyPort(8090);
configuration.setProxyUser("tricia");
configuration.setProxyPassword("tricias secret");
configuration.setEnableProxy(true);
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").request();
assertTrue(client.proxyConnection);
verify(connection).addRequestProperty(
DefaultAdvancedHttpClient.HEADER_PROXY_AUTHORIZATION,
"Basic dHJpY2lhOnRyaWNpYXMgc2VjcmV0");
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*/
@Before
public void setUp()
{
configuration = new ScmConfiguration();
transformers = new HashSet<ContentTransformer>();
client = new TestingAdvacedHttpClient(configuration, transformers);
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 15/05/01
* @author Enter your name here...
*/
public class TestingAdvacedHttpClient extends DefaultAdvancedHttpClient
{
/**
* Constructs ...
*
*
* @param configuration
* @param transformers
*/
public TestingAdvacedHttpClient(ScmConfiguration configuration,
Set<ContentTransformer> transformers)
{
super(configuration, transformers);
}
//~--- methods ------------------------------------------------------------
/**
* Method description
*
*
* @param url
*
* @return
*
* @throws IOException
*/
@Override
protected HttpURLConnection createConnection(URL url) throws IOException
{
return connection;
}
/**
* Method description
*
*
* @param url
* @param address
*
* @return
*
* @throws IOException
*/
@Override
protected HttpURLConnection createProxyConnecton(URL url,
SocketAddress address)
throws IOException
{
proxyConnection = true;
return connection;
}
//~--- fields -------------------------------------------------------------
/** Field description */
private boolean proxyConnection = false;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private TestingAdvacedHttpClient client;
/** Field description */
private ScmConfiguration configuration;
/** Field description */
@Mock
private HttpsURLConnection connection;
/** Field description */
private Set<ContentTransformer> transformers;
}

View File

@@ -0,0 +1,151 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.config.ScmConfiguration;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultAdvancedHttpResponseTest
{
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testContentAsByteSource() throws IOException
{
ByteArrayInputStream bais =
new ByteArrayInputStream("test".getBytes(Charsets.UTF_8));
when(connection.getInputStream()).thenReturn(bais);
AdvancedHttpResponse response = new DefaultAdvancedHttpResponse(client,
connection, 200, "OK");
ByteSource content = response.contentAsByteSource();
assertEquals("test", content.asCharSource(Charsets.UTF_8).read());
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testContentAsByteSourceWithFailedRequest() throws IOException
{
ByteArrayInputStream bais =
new ByteArrayInputStream("test".getBytes(Charsets.UTF_8));
when(connection.getInputStream()).thenThrow(IOException.class);
when(connection.getErrorStream()).thenReturn(bais);
AdvancedHttpResponse response = new DefaultAdvancedHttpResponse(client,
connection, 404, "NOT FOUND");
ByteSource content = response.contentAsByteSource();
assertEquals("test", content.asCharSource(Charsets.UTF_8).read());
}
/**
* Method description
*
*/
@Test
public void testGetHeaders()
{
LinkedHashMap<String, List<String>> map = Maps.newLinkedHashMap();
List<String> test = Lists.newArrayList("One", "Two");
map.put("Test", test);
when(connection.getHeaderFields()).thenReturn(map);
AdvancedHttpResponse response = new DefaultAdvancedHttpResponse(client,
connection, 200, "OK");
Multimap<String, String> headers = response.getHeaders();
assertThat(headers.get("Test"), contains("One", "Two"));
assertTrue(headers.get("Test-2").isEmpty());
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final DefaultAdvancedHttpClient client =
new DefaultAdvancedHttpClient(new ScmConfiguration(),
new HashSet<ContentTransformer>());
/** Field description */
@Mock
private HttpURLConnection connection;
}

View File

@@ -0,0 +1,92 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.io.ByteSource;
import java.io.IOException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
*
* @author Sebastian Sdorra
*/
public class JsonContentTransformerTest {
private final JsonContentTransformer transformer = new JsonContentTransformer();
@Test
public void testIsResponsible()
{
assertTrue(transformer.isResponsible(String.class, "application/json"));
assertTrue(transformer.isResponsible(String.class, "application/json;charset=UTF-8"));
assertFalse(transformer.isResponsible(String.class, "text/plain"));
}
@Test
public void testMarshallAndUnmarshall() throws IOException{
ByteSource bs = transformer.marshall(new TestObject("test"));
TestObject to = transformer.unmarshall(TestObject.class, bs);
assertEquals("test", to.value);
}
@Test(expected = ContentTransformerException.class)
public void testUnmarshallIOException() throws IOException{
ByteSource bs = mock(ByteSource.class);
when(bs.openBufferedStream()).thenThrow(IOException.class);
transformer.unmarshall(String.class, bs);
}
private static class TestObject2 {}
@XmlRootElement(name = "test")
@XmlAccessorType(XmlAccessType.FIELD)
private static class TestObject {
private String value;
public TestObject()
{
}
public TestObject(String value)
{
this.value = value;
}
}
}

View File

@@ -0,0 +1,92 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.io.ByteSource;
import java.io.IOException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
*
* @author Sebastian Sdorra
*/
public class XmlContentTransformerTest {
private final XmlContentTransformer transformer = new XmlContentTransformer();
@Test
public void testIsResponsible()
{
assertTrue(transformer.isResponsible(String.class, "application/xml"));
assertTrue(transformer.isResponsible(String.class, "application/xml;charset=UTF-8"));
assertFalse(transformer.isResponsible(String.class, "text/plain"));
}
@Test
public void testMarshallAndUnmarshall() throws IOException{
ByteSource bs = transformer.marshall(new TestObject("test"));
TestObject to = transformer.unmarshall(TestObject.class, bs);
assertEquals("test", to.value);
}
@Test(expected = ContentTransformerException.class)
public void testUnmarshallIOException() throws IOException{
ByteSource bs = mock(ByteSource.class);
when(bs.openBufferedStream()).thenThrow(IOException.class);
transformer.unmarshall(String.class, bs);
}
private static class TestObject2 {}
@XmlRootElement(name = "test")
@XmlAccessorType(XmlAccessType.FIELD)
private static class TestObject {
private String value;
public TestObject()
{
}
public TestObject(String value)
{
this.value = value;
}
}
}