All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cloudesire.tisana4j.RestClient Maven / Gradle / Ivy

package com.cloudesire.tisana4j;

import com.cloudesire.tisana4j.ExceptionTranslator.ResponseMessage;
import com.cloudesire.tisana4j.exceptions.BadRequestException;
import com.cloudesire.tisana4j.exceptions.DefaultExceptionTranslator;
import com.cloudesire.tisana4j.exceptions.ExceptionFactory;
import com.cloudesire.tisana4j.exceptions.ParseException;
import com.cloudesire.tisana4j.exceptions.RestException;
import com.cloudesire.tisana4j.exceptions.RuntimeRestException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.DateUtils;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class RestClient implements RestClientInterface
{
    private static final Logger log = LoggerFactory.getLogger( RestClient.class );
    private static final Object jaxbGuard = new Object();
    private final String username;
    private final String password;
    private ObjectMapper mapper = new ObjectMapper();
    private final boolean skipValidation;
    private int CONNECTION_TIMEOUT = 60000 * 2;
    private int SOCKET_TIMEOUT = 60000 * 2;
    private boolean authenticated;
    private boolean useXml = false;
    private ExceptionTranslator exceptionTranslator = new DefaultExceptionTranslator();
    private boolean skipContentCompression = false;
    private Map headers;
    private Map> responseHeaders;
    private SSLContext ctx;
    private HttpClient httpClient;
    private String proxyHostname;
    private int proxyPort = 8080;
    private String proxyScheme = "http";
    private int httpClientMaxConnPerRoute = 2;
    private int httpClientMaxConnTotal = 20;

    /**
     * Default settings: no authentication and verify if server certificate is
     * valid. Uses json. For use xml setUseXml() to true.
     */
    public RestClient()
    {
        this( null, null, false, null );
    }

    /**
     * @param skipValidation if true skips server certificate validation for Https
     *                       connections
     */
    public RestClient( boolean skipValidation )
    {
        this( null, null, skipValidation, null );
    }

    /**
     * @param username       user for authentication
     * @param password       password for authentication
     * @param skipValidation if true skips server certificate validation for Https
     *                       connections
     */
    public RestClient( String username, String password, boolean skipValidation )
    {
        this( username, password, skipValidation, null );
    }

    /**
     * @param username       user for authentication
     * @param password       password for authentication
     * @param skipValidation if true skips server certificate validation for Https
     *                       connections
     * @param headers        connection properties that will be added by default to any
     *                       connection
     */
    public RestClient( String username, String password, boolean skipValidation, Map headers )
    {
        this( username, password, skipValidation, headers, null );
    }

    /**
     * @param username       user for authentication
     * @param password       password for authentication
     * @param skipValidation if true skips server certificate validation for Https
     *                       connections
     * @param headers        connection properties that will be added by default to any
     *                       connection
     * @param ctx            ssl context
     */
    public RestClient( String username, String password, boolean skipValidation, Map headers,
            SSLContext ctx )
    {
        this( username, password, skipValidation, headers, ctx, null, null );

    }

    /**
     * @param username          user for authentication
     * @param password          password for authentication
     * @param skipValidation    if true skips server certificate validation for Https
     *                          connections
     * @param headers           connection properties that will be added by default to any
     *                          connection
     * @param ctx               ssl context
     * @param connectionTimeOut connection timeout Milliseconds - default 2 minutes
     * @param socketTimeOut     socket timeout Milliseconds - default 2 minutes
     */
    public RestClient( String username, String password, boolean skipValidation, Map headers,
            SSLContext ctx, Integer connectionTimeOut, Integer socketTimeOut )
    {
        super();
        this.username = username;
        this.password = password;
        this.skipValidation = skipValidation;
        authenticated = username != null;
        this.headers = headers;
        this.ctx = ctx;
        if ( connectionTimeOut != null ) this.CONNECTION_TIMEOUT = connectionTimeOut;
        if ( socketTimeOut != null ) this.SOCKET_TIMEOUT = socketTimeOut;
    }

    public RestClient( RestClientBuilder builder )
    {
        this( builder.getUsername(), builder.getPassword(), builder.getSkipValidation(), builder.getHeaders(),
                null, builder.getConnectionTimeout(), builder.getSocketTimeout() );
        this.proxyHostname = builder.getProxyHostname();
        this.proxyPort = builder.getProxyPort();
        this.proxyScheme = builder.getProxyScheme();
    }

    // wrap newInstance to avoid http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7122142
    private static JAXBContext getJaxbContext( Class clazz ) throws JAXBException
    {
        synchronized ( jaxbGuard )
        {
            return JAXBContext.newInstance( clazz );
        }
    }

    @Override
    public void toggleAuthentication()
    {
        authenticated = !authenticated;
    }

    @Override
    public String getUsername()
    {
        return username;
    }

    @Override
    public void delete( URL url ) throws RestException
    {
        delete( url, null );
    }

    private Map> parseResponseHeaders( HttpResponse response )
    {
        responseHeaders = new HashMap<>();
        if ( response.getAllHeaders().length != 0 )
        {
            for ( Header header : response.getAllHeaders() )
            {
                String name = header.getName();
                String value = header.getValue();
                if ( responseHeaders.containsKey( name ) ) responseHeaders.get( name ).add( value );
                else
                {
                    List x = new LinkedList<>();
                    x.add( value );
                    responseHeaders.put( name, x );
                }
            }
        }
        return responseHeaders;
    }

    @Override
    public void delete( URL url, Map newHeaders ) throws RestException
    {
        HttpDelete delete;
        try
        {
            delete = new HttpDelete( url.toURI() );
        }
        catch ( URISyntaxException e )
        {
            throw new RuntimeRestException( e );
        }
        prepareRequest( delete, newHeaders );
        HttpResponse response = execute( delete );
        parseResponseHeaders( response );
        EntityUtils.consumeQuietly( response.getEntity() );
    }

    @Override
    public  T get( URL url, Class clazz ) throws RestException
    {
        return get( url, clazz, null );
    }

    @Override
    public  T get( URL url, TypeReference typeReference ) throws RestException, RuntimeRestException
    {
        return get( url, typeReference, null );
    }

    @Override
    public  T get( URL url, Class clazz, Map newHeaders )
            throws RestException
    {
        try
        {
            HttpResponse response = getInternal( url, newHeaders );
            return readObject( clazz, response );
        }
        catch ( ParseException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public  T get( URL url, TypeReference typeReference, Map newHeaders )
            throws RestException, RuntimeRestException
    {
        try
        {
            HttpResponse response = getInternal( url, newHeaders );
            return readJsonObject( typeReference, response );
        }
        catch ( ParseException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    private HttpResponse getInternal( URL url, Map headers ) throws RestException
    {
        try
        {
            HttpGet get = new HttpGet( url.toURI() );
            prepareRequest( get, headers );
            return execute( get );
        }
        catch ( URISyntaxException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public InputStream get( URL url ) throws RestException
    {
        try
        {
            return getInternal( url, new HashMap() ).getEntity().getContent();
        }
        catch ( IOException e )
        {
            throw new RestException( e );
        }
    }

    @Override
    public InputStream get( URL url, Map headers )
            throws RestException
    {
        try
        {
            return getInternal( url, headers ).getEntity().getContent();
        }
        catch ( IOException e )
        {
            throw new RestException( e );
        }
    }

    @Override
    public  List getCollection( URL url, Class clazz ) throws RestException
    {
        return getCollection( url, clazz, null );

    }

    @Override
    public  List getCollection( URL url, Class clazz, Map newHeaders )
            throws RestException
    {
        try
        {
            HttpGet get = new HttpGet( url.toURI() );
            prepareRequest( get, newHeaders );
            HttpResponse response = execute( get );
            parseResponseHeaders( response );
            try ( InputStream stream = response.getEntity().getContent() )
            {
                return mapper.reader( mapper.getTypeFactory().constructCollectionType( List.class, clazz ) )
                        .readValue( stream );
            }
        }
        catch ( IOException | URISyntaxException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public Map head( URL url ) throws RuntimeRestException, RestException
    {
        return head( url, null );
    }

    @Override
    public Map head( URL url, Map newHeaders )
            throws RestException
    {
        try
        {
            HttpHead head = new HttpHead( url.toURI() );
            prepareRequest( head, newHeaders );
            HttpResponse response = execute( head );
            EntityUtils.consumeQuietly( response.getEntity() );

            Map headers = new HashMap<>();
            Header[] allHeaders = response.getAllHeaders();
            if ( allHeaders == null ) return headers;
            for ( Header allHeader : allHeaders )
                headers.put( allHeader.getName(), allHeader.getValue() );
            return headers;
        }
        catch ( URISyntaxException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public String[] options( URL url ) throws RestException
    {
        return options( url, null );
    }

    @Override
    public String[] options( URL url, Map newHeaders ) throws RestException
    {
        HttpOptions options;
        try
        {
            options = new HttpOptions( url.toURI() );
        }
        catch ( URISyntaxException e )
        {
            throw new RuntimeRestException( e );
        }
        prepareRequest( options, newHeaders );
        HttpResponse response = execute( options );
        EntityUtils.consumeQuietly( response.getEntity() );
        String allow = null;
        Header[] allHeaders = response.getAllHeaders();
        for ( Header allHeader : allHeaders )
            if ( Objects.equals( allHeader.getName(), "Allow" ) ) allow = allHeader.getValue();
        if ( allow == null ) throw new BadRequestException( 404, "Method options not supported." );
        return allow.split( "," );
    }

    @Override
    public  T patchEntity( URL url, Map paramMap, Class clazz )
            throws RestException
    {
        return patchEntity( url, paramMap, clazz, null );
    }

    @Override
    public  T patchEntityO( URL url, Map paramMap, Class clazz )
            throws RestException
    {
        return patchEntityO( url, paramMap, clazz, null );
    }

    @Override
    public  T patchEntity( URL url, Map paramMap, Class clazz, Map newHeaders )
            throws RestException
    {
        return patchEntityO( url, paramMap != null ? new HashMap( paramMap ) : null, clazz,
                newHeaders );
    }

    @Override
    public  T patchEntityO( URL url, Map paramMap, Class clazz, Map newHeaders )
            throws RestException
    {
        try
        {
            HttpPatch patch = new HttpPatch( url.toURI() );

            prepareRequest( patch, newHeaders );
            writeObject( paramMap, patch );
            return readObject( clazz, execute( patch ) );
        }
        catch ( URISyntaxException | ParseException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public void patch( URL url, Object object ) throws RestException
    {
        patch( url, object, null );
    }

    @Override
    public void patch( URL url, Object object, Map newHeaders ) throws RestException
    {
        try
        {
            HttpPatch patch = new HttpPatch( url.toURI() );

            prepareRequest( patch, newHeaders );
            writeObject( object, patch );
            HttpResponse response = execute( patch );
            parseResponseHeaders( response );
            EntityUtils.consumeQuietly( response.getEntity() );
        }
        catch ( URISyntaxException | ParseException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public void patchO( URL url, Map paramMap ) throws RestException
    {
        patch( url, paramMap, null );
    }

    @Override
    public void patchO( URL url, Map paramMap, Map newHeaders ) throws RestException
    {
        patch( url, paramMap, newHeaders );
    }

    @Override
    public  T post( URL url, T obj ) throws RestException
    {
        return post( url, obj, null );
    }

    @Override
    @SuppressWarnings ( "unchecked" )
    public  T post( URL url, T obj, Map newHeaders ) throws RestException
    {
        return (T) post( url, obj, newHeaders, obj.getClass() );
    }

    @Override
    public  R post( URL url, T obj, Map newHeaders, Class responseClass )
            throws RestException
    {
        try
        {
            HttpPost post = new HttpPost( url.toURI() );

            prepareRequest( post, newHeaders );
            writeObject( obj, post );
            HttpResponse response = execute( post );

            if ( response.getEntity() == null )
            {
                parseResponseHeaders( response );
                return null;
            }
            if ( responseClass == null )
            {
                parseResponseHeaders( response );
                EntityUtils.consumeQuietly( response.getEntity() );
                return null;
            }
            return readObject( responseClass, response );
        }
        catch ( URISyntaxException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public  T postData( URL url, String filename, InputStream content, Class responseClass )
            throws RestException
    {
        return postData( url, filename, content, responseClass, null );
    }

    @Override
    public  T postData( URL url, String filename, InputStream content, Class responseClass,
            Map newHeaders ) throws RestException
    {

        try
        {
            HttpPost post = new HttpPost( url.toURI() );

            prepareRequest( post, newHeaders );

            InputStreamBody body = new InputStreamBody( content, filename );

            HttpEntity entity = MultipartEntityBuilder.create()
                    .addPart( "file", body )
                    .build();

            post.setEntity( entity );
            HttpResponse response = execute( post );
            if ( responseClass == null || response.getEntity() == null )
            {
                parseResponseHeaders( response );
                EntityUtils.consumeQuietly( response.getEntity() );
                return null;
            }
            return readObject( responseClass, response );
        }
        catch ( URISyntaxException | ParseException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public  T postFormData( URL url, List pairs, Class responseClass )
            throws RestException
    {
        try
        {
            HttpPost post = new HttpPost( url.toURI() );
            prepareRequest( post, null );

            List formData = new ArrayList<>();
            for ( Pair pair: pairs )
            {
                formData.add( new BasicNameValuePair( pair.getKey(), pair.getValue() ) );
            }

            UrlEncodedFormEntity entity = new UrlEncodedFormEntity( formData, "UTF-8" );
            post.setEntity( entity );
            HttpResponse response = execute( post );
            if ( responseClass == null || response.getEntity() == null )
            {
                parseResponseHeaders( response );
                EntityUtils.consumeQuietly( response.getEntity() );
                return null;
            }
            return readObject( responseClass, response );
        }
        catch ( URISyntaxException | UnsupportedEncodingException | ParseException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public  T put( URL url, T obj ) throws RestException
    {
        return put( url, obj, null );
    }

    @SuppressWarnings ( "unchecked" )
    @Override
    public  T put( URL url, T obj, Map newHeaders ) throws RestException
    {
        return (T) put( url, obj, newHeaders, obj.getClass() );
    }

    @Override
    public  R put( URL url, T obj, Map newHeaders, Class responseClass )
            throws RestException
    {
        try
        {
            HttpPut put = new HttpPut( url.toURI() );
            prepareRequest( put, newHeaders );
            writeObject( obj, put );
            HttpResponse response = execute( put );
            if ( response.getEntity() == null )
            {
                parseResponseHeaders( response );
                return null;
            }
            return readObject( responseClass, response );
        }
        catch ( URISyntaxException | ParseException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public void setExceptionTranslator( ExceptionTranslator exceptionTranslator )
    {
        this.exceptionTranslator = exceptionTranslator;
    }

    @Override
    public Map getHeaders()
    {
        return this.headers;
    }

    @Override
    public void setHeaders( Map headers )
    {
        this.headers = headers;
    }

    @Override
    public void setUseXml( boolean useXml )
    {
        this.useXml = useXml;
    }

    private void applyHeaders( HttpRequest request, Map newHeaders )
    {
        Map mergedHeaders = new HashMap<>();
        if ( headers != null ) mergedHeaders.putAll( headers );
        if ( newHeaders != null ) mergedHeaders.putAll( newHeaders );

        for ( String k : mergedHeaders.keySet() )
            request.addHeader( k, mergedHeaders.get( k ) );
    }

    private void checkError( HttpResponse response ) throws RestException
    {
        int responseCode = response.getStatusLine().getStatusCode();
        if ( responseCode < 200 || responseCode >= 300 )
        {
            try ( InputStream stream = response.getEntity().getContent() )
            {
                ContentType type = ContentType.getOrDefault( response.getEntity() );
                String charset = type.getCharset() != null ? type.getCharset().name() : "UTF-8";

                String errorStream = IOUtils.toString( stream, charset );

                ResponseMessage responseMessage = new ResponseMessage();
                RestException translatedException = exceptionTranslator
                        .translateException( responseCode, response.getStatusLine().getReasonPhrase(), errorStream,
                                responseMessage, response.getAllHeaders() );

                if ( translatedException != null ) throw translatedException;

                throw getDefaultException( responseCode, response.getStatusLine().getReasonPhrase(),
                        responseMessage.getResponse() != null ? responseMessage.getResponse() : errorStream );

            }
            catch ( IllegalStateException | IOException e )
            {
                throw new RestException( responseCode, e.getMessage() );
            }
        }
    }

    private RestException getDefaultException( int responseCode, String reasonPhrase, String responseMessage )
    {
        return ExceptionFactory.getException( responseCode, reasonPhrase, responseMessage );
    }

    /**
     * Internal execute, log headers, check for errors
     *
     * @param request The request object to be executed
     *
     * @return HttpResponse Response replied by the server
     *
     * @throws RestException
     */
    private HttpResponse execute( HttpUriRequest request ) throws RestException
    {
        log.debug( ">>>> " + request.getRequestLine() );
        for ( Header header : request.getAllHeaders() )
        {
            log.trace( ">>>> " + header.getName() + ": " + header.getValue() );
        }

        HttpResponse response;
        try
        {
            response = getHttpClient().execute( request );
            log.debug( "<<<< " + response.getStatusLine() );
            for ( Header header : response.getAllHeaders() )
            {
                log.trace( "<<<< " + header.getName() + ": " + header.getValue() );
            }

            if ( response.getStatusLine().getStatusCode() == 204 )
            {
                log.debug( "Consuming quietly the response entity since server returned no content" );
                EntityUtils.consumeQuietly( response.getEntity() );
            }

            checkError( response );
            return response;
        }
        catch ( KeyManagementException | NoSuchAlgorithmException | IOException e )
        {
            throw new RuntimeRestException( e );
        }
        finally
        {
            // https://issues.apache.org/jira/browse/HTTPCLIENT-1523
            DateUtils.clearThreadLocal();
        }
    }

    private synchronized HttpClient getHttpClient() throws KeyManagementException, NoSuchAlgorithmException
    {
        if ( httpClient == null )
        {
            HttpClientBuilder httpClientBuilder = HttpClients.custom()
                    .setMaxConnPerRoute( httpClientMaxConnPerRoute )
                    .setMaxConnTotal( httpClientMaxConnTotal );

            final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom()
                    .setConnectionRequestTimeout( CONNECTION_TIMEOUT )
                    .setSocketTimeout( SOCKET_TIMEOUT );

            if ( proxyHostname != null )
            {
                HttpHost proxy = new HttpHost( proxyHostname, proxyPort, proxyScheme );
                requestConfigBuilder.setProxy( proxy );
            }
            else if ( System.getProperty( "http.proxyHost" ) != null )
            {
                if ( System.getProperty( "http.proxyPort" ) != null )
                {
                    proxyPort = Integer.valueOf( System.getProperty( "http.proxyPort" ) );
                }

                HttpHost proxy = new HttpHost( System.getProperty( "http.proxyHost" ), proxyPort, proxyScheme );
                requestConfigBuilder.setProxy( proxy );
            }

            RequestConfig requestConfig = requestConfigBuilder.build();

            SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive( true ).setSoTimeout( SOCKET_TIMEOUT )
                    .build();

            httpClientBuilder.setDefaultRequestConfig( requestConfig ).setDefaultSocketConfig( socketConfig );

            if ( skipContentCompression ) httpClientBuilder.disableContentCompression();

            if ( skipValidation || ctx != null )
            {
                try
                {
                    if ( ctx != null )
                    {
                        httpClientBuilder.setSslcontext( ctx );
                    }
                    else
                    {
                        SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial( new TrustStrategy()
                        {
                            @Override
                            public boolean isTrusted( X509Certificate[] chain, String authType )
                                    throws CertificateException
                            {
                                return true;
                            }
                        } ).build();

                        httpClientBuilder.setSslcontext( sslContext );
                    }

                    httpClientBuilder.setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE );
                }
                catch ( KeyStoreException e )
                {
                    log.warn( "Cannot setup skipValidation", e );
                }
            }



            httpClient = httpClientBuilder.build();
        }

        return httpClient;
    }

    private  T readObject( Class clazz, HttpResponse response )
    {
        parseResponseHeaders( response );
        if ( response.getEntity() == null ) return null;

        if ( clazz.isAssignableFrom( InputStream.class ) )
        {
            try
            {
                return (T) response.getEntity().getContent();
            }
            catch ( IOException ex )
            {
                throw new RuntimeRestException( ex );
            }
        }

        Header contentType = response.getEntity().getContentType();
        if ( contentType != null )
        {
            if ( contentType.getValue().contains( ContentType.APPLICATION_JSON.getMimeType() ) )
                return parseJson( clazz, response );
            if ( contentType.getValue().toLowerCase().contains( "xml" ) ) return parseXml( clazz, response );
            if ( contentType.getValue().contains( ContentType.TEXT_PLAIN.getMimeType() ) ) try
            {
                return (T) IOUtils.toString( response.getEntity().getContent() );
            }
            catch ( IOException e )
            {
                throw new RuntimeRestException( e );
            }
        }
        throw new ParseException(
                "Unsupported content type " + ( contentType != null ? contentType.getValue() : "null" ) );
    }

    private  T readJsonObject( TypeReference typeReference, HttpResponse response ) throws RuntimeRestException
    {
        Header contentType = response.getEntity().getContentType();
        if ( contentType != null )
        {
            if ( contentType.getValue().contains( ContentType.APPLICATION_JSON.getMimeType() ) )
                return parseJson( typeReference, response );
        }
        throw new ParseException(
                "Unsupported content type " + ( contentType != null ? contentType.getValue() : "null" ) );
    }

    private  T parseJson( Class clazz, HttpResponse response )
    {
        return internalParseJson( clazz, response );
    }

    private  T parseJson( TypeReference typeReference, HttpResponse response ) throws RuntimeRestException
    {
        return internalParseJson( typeReference, response );
    }

    @SuppressWarnings("unchecked")
    private  T internalParseJson( Object parameter, HttpResponse response ) throws RuntimeRestException
    {
        try ( InputStream stream = response.getEntity().getContent() )
        {
            if ( parameter instanceof Class)
            {
                Class clazz = (Class) parameter;
                return mapper.reader( clazz ).readValue( stream );
            }
            if ( parameter instanceof TypeReference)
            {
                TypeReference clazz = (TypeReference) parameter;
                return mapper.reader( clazz ).readValue( stream );
            }
            throw new IllegalArgumentException( "First parameter should be a Class or a TypeReference" );
        }
        catch ( JsonProcessingException e )
        {
            throw new ParseException( e );
        }
        catch ( IllegalStateException | IOException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    private  T parseXml( Class clazz, HttpResponse response )
    {
        try ( InputStream stream = response.getEntity().getContent() )
        {
            JAXBContext contextB = getJaxbContext( clazz );
            Unmarshaller unmarshallerB = contextB.createUnmarshaller();
            try
            {
                return (T) unmarshallerB.unmarshal( stream );
            }
            catch ( JAXBException e )
            {
                throw new ParseException( e );
            }
        }
        catch ( IllegalStateException | IOException | JAXBException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    private void prepareRequest( HttpRequest request, Map newHeaders )
    {
        applyHeaders( request, newHeaders );
        if ( authenticated )
        {
            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( username, password );
            try
            {
                request.addHeader( new BasicScheme().authenticate( credentials, request, null ) );
            }
            catch ( AuthenticationException e )
            {
                log.warn( "it should not happens", e );
            }
        }
    }

    private  void writeObject( T obj, HttpEntityEnclosingRequest request ) throws ParseException
    {
        if ( obj == null ) return;
        String payload = useXml ? serializeXMLContent( obj, request ) : serializeJsonContent( obj, request );
        HttpRequestBase httpRequest = (HttpRequestBase) request;
        log.debug( "{} payload: {}", httpRequest.getMethod(), payload );
    }

    private  String serializeJsonContent( T obj, HttpEntityEnclosingRequest request ) throws ParseException
    {
        try
        {
            request.addHeader( "Content-type", "application/json" );
            ObjectWriter writer = mapper.writer();
            String payload = writer.writeValueAsString( obj );
            StringEntity entity = new StringEntity( payload, ContentType.APPLICATION_JSON );
            request.setEntity( entity );
            return payload;
        }
        catch ( JsonProcessingException e )
        {
            throw new ParseException( e );
        }
    }

    private  String serializeXMLContent( T obj, HttpEntityEnclosingRequest request )
    {
        request.addHeader( "Content-type", "application/xml" );
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        JAXBContext context;
        try
        {
            context = JAXBContext.newInstance( obj.getClass() );
            Marshaller m = context.createMarshaller();
            m.marshal( obj, baos );
            String payload = baos.toString();
            StringEntity entity = new StringEntity( payload, ContentType.APPLICATION_XML );
            request.setEntity( entity );
            return payload;
        }
        catch ( JAXBException e )
        {
            throw new ParseException( e );
        }
    }

    @Override
    public InputStream getData( URL url, Map newHeaders ) throws RestException
    {
        try
        {
            HttpGet get;
            get = new HttpGet( url.toURI() );
            prepareRequest( get, newHeaders );
            HttpResponse response = execute( get );
            return response.getEntity().getContent();
        }
        catch ( URISyntaxException | IllegalStateException | IOException e )
        {
            throw new RuntimeRestException( e );
        }
    }

    @Override
    public Map> getLastResponseHeaders()
    {
        return responseHeaders;
    }

    /**
     * Use to disable content compression
     * @param disableContentCompression true if content compression should be disabled
     */
    @Override
    public void setHttpContentCompressionOverride( boolean disableContentCompression )
    {
        settingsAlreadyInitializedCheck();
        this.skipContentCompression = disableContentCompression;
    }

    /**
     * Change failure behaviour in deserialization if an unknown field is found
     * @param flag if true fail, if false ignore unknown field
     */
    @Override
    public void setObjectMapperFailOnUknownField( boolean flag )
    {
        this.mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, flag );
    }

    /**
     * Enable proxy support
     * @param proxyHostname proxy hostname
     */
    @Override
    public void setProxyHostname( String proxyHostname )
    {
        settingsAlreadyInitializedCheck();
        this.proxyHostname = proxyHostname;
    }

    /**
     * Change port of proxy
     * @param proxyPort the port number of the proxy server
     */
    @Override
    public void setProxyPort( int proxyPort )
    {
        settingsAlreadyInitializedCheck();
        this.proxyPort = proxyPort;
    }

    /**
     * Proxy protocol (default "http")
     * @param proxyScheme http or https
     */
    @Override
    public void setProxyScheme( String proxyScheme )
    {
        settingsAlreadyInitializedCheck();
        this.proxyScheme = proxyScheme;
    }

    @Override
    public void setHttpClientMaxConnectionsPerRoute( int httpClientMaxConnPerRoute )
    {
        settingsAlreadyInitializedCheck();
        this.httpClientMaxConnPerRoute = httpClientMaxConnPerRoute;
    }

    @Override
    public void setHttpClientMaxConnTotal( int httpClientMaxConnTotal )
    {
        settingsAlreadyInitializedCheck();
        this.httpClientMaxConnTotal = httpClientMaxConnTotal;
    }

    @Deprecated
    @Override
    public ObjectMapper getObjectMapper()
    {
        return mapper;
    }

    @Override
    public void setObjectMapper( ObjectMapper mapper )
    {
        this.mapper = mapper;
    }

    private void settingsAlreadyInitializedCheck()
    {
        if ( httpClient != null )
            throw new IllegalArgumentException( "httpClient already initialized, too late to change behaviour" );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy