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

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved.
 */

package com.sap.cloud.sdk.cloudplatform.connectivity;

import java.net.URI;
import java.net.URISyntaxException;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;

import com.sap.cloud.sdk.cloudplatform.connectivity.exception.DestinationPathsNotMergeableException;
import com.sap.cloud.sdk.cloudplatform.exception.ShouldNotHappenException;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;

/**
 * Utility class offering the ability to merge two URIs.
 */
public class UriPathMerger
{
    private static final Logger logger = CloudLoggerFactory.getLogger(UriPathMerger.class);

    /**
     * Merges two {@code URI} paths, checking that both {@code URIs} have the same scheme, host and port.
     *
     * @param destinationUri
     *            The {@code URI} pointing to the destination.
     * @param requestUri
     *            The {@code URI} identifying the request.
     *
     * @throws DestinationPathsNotMergeableException
     *             If either of the request paths of the the given URIs are {@code null} or the URIs differ in the used
     *             schema, host, or port.
     *
     * @return The merged {@code URI}, representing the given request executed on the given destination.
     */
    @Nonnull
    public URI merge( @Nonnull final URI destinationUri, @Nullable final URI requestUri )
        throws DestinationPathsNotMergeableException
    {
        try {
            if( requestUri != null ) {
                String requestRawPath = requestUri.getRawPath();

                if( logger.isDebugEnabled() ) {
                    logger.debug("Merging request path: " + requestRawPath);
                }

                final String destinationUriRawPath = destinationUri.getRawPath();
                assertRequestUriMatchesDestinationUri(destinationUri, requestUri);

                if( logger.isDebugEnabled() ) {
                    logger.debug("Successfully merged request path: " + requestRawPath);
                }

                // If the request path is relative we need to merge it with the destination path.
                // If, instead, the request path is absolute, then the request path already contains the full path
                // and doesn't need to be merged with the destination path.
                if( !requestUri.isAbsolute() ) {
                    requestRawPath = mergeUriRawPaths(destinationUriRawPath, requestRawPath);
                }

                final URI mergedUri = destinationUri.resolve(requestRawPath);

                return new URIBuilder(mergedUri)
                    .setUserInfo(requestUri.getUserInfo())
                    .setCustomQuery(requestUri.getQuery())
                    .setFragment(requestUri.getFragment())
                    .build();
            } else {
                String requestRawPath = destinationUri.getRawPath();
                requestRawPath = requestRawPath.replaceAll("^/", "");
                requestRawPath = "/" + requestRawPath;

                return new URIBuilder(destinationUri).setPath(requestRawPath).build();
            }
        }
        catch( final URISyntaxException e ) {
            throw new ShouldNotHappenException("Failed to merge request URI.", e);
        }
    }

    private
        void
        assertRequestUriMatchesDestinationUri( @Nonnull final URI destinationUri, @Nonnull final URI requestUri )
            throws DestinationPathsNotMergeableException
    {
        if( requestUri.getHost() != null ) {
            final boolean isSchemeEqual = destinationUri.getScheme().equalsIgnoreCase(requestUri.getScheme());
            final boolean isHostEqual = destinationUri.getHost().equalsIgnoreCase(requestUri.getHost());
            final boolean isPortEqual = destinationUri.getPort() == requestUri.getPort();

            if( !(isSchemeEqual && isHostEqual && isPortEqual) ) {
                throw new DestinationPathsNotMergeableException(
                    "URIs defined in destination '"
                        + destinationUri
                        + "' and supplied by application code '"
                        + requestUri
                        + "' differ.");
            }
        }
    }

    /**
     * Merges two {@link URI} paths into one, preventing path duplications.
     *
     * @throws DestinationPathsNotMergeableException
     *             If either of the given paths is {@code null}.
     *
     * @return The merged path as String.
     */
    @Nonnull
    private String mergeUriRawPaths( @Nullable final String firstRawPath, @Nullable final String secondRawPath )
        throws DestinationPathsNotMergeableException
    {
        if( firstRawPath == null || secondRawPath == null ) {
            throw new DestinationPathsNotMergeableException("Cannot merge URI paths that are null.");
        }

        final String first = firstRawPath.trim().replaceFirst("^/", "");
        final String second = secondRawPath.trim().replaceFirst("^/", "");

        final String result;

        if( second.isEmpty() ) {
            result = first;
        } else {
            if( second.startsWith(first) ) {
                result = second;
            } else {
                result = (first.endsWith("/") ? first : first + "/") + second;
            }
        }

        return result.startsWith("/") ? result : "/" + result;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy