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

com.sap.cloud.yaas.servicesdk.apiconsole.web.ApiConsoleEndpoint Maven / Gradle / Ivy

There is a newer version: 4.17.1
Show newest version
/*
 * © 2016 SAP SE or an SAP affiliate company.
 * All rights reserved.
 * Please see http://www.sap.com/corporate-en/legal/copyright/index.epx for additional trademark information and
 * notices.
 */
package com.sap.cloud.yaas.servicesdk.apiconsole.web;

import com.sap.cloud.yaas.servicesdk.apiconsole.model.AppInfo;
import com.sap.cloud.yaas.servicesdk.apiconsole.utils.ApiConsoleLocationProvider;
import com.sap.cloud.yaas.servicesdk.apiconsole.utils.AppInfoReader;
import com.sap.cloud.yaas.servicesdk.apiconsole.utils.RamlFilePathProvider;
import com.sap.cloud.yaas.servicesdk.apiconsole.utils.StaticResourceUtils;
import com.sap.cloud.yaas.servicesdk.ramlrewriter.filter.ExternalUrlHeaderUtil;
import com.sap.cloud.yaas.servicesdk.ramlrewriter.mappings.TraitMappings;
import com.sap.cloud.yaas.servicesdk.ramlrewriter.mutators.ExpandingMode;
import com.sap.cloud.yaas.servicesdk.ramlrewriter.mutators.LineMutator;
import com.sap.cloud.yaas.servicesdk.ramlrewriter.mutators.line.LineMutatorsFactory;
import com.sap.cloud.yaas.servicesdk.security.SecurityUtils;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.List;

import javax.servlet.ServletContext;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Resource serves static content and RAML resources for api console.
 */
@Path("/api-console")
public class ApiConsoleEndpoint
{
	private static final Logger LOG = LoggerFactory.getLogger(ApiConsoleEndpoint.class);
	private static final String STATIC_CONTENTS_SUBPACKAGE = "static";
	private static final String INDEX = "index.html";

	private final LineMutatorsFactory lineMutatorFactory = new LineMutatorsFactory();
	private final AppInfoReader appInfoReader = new AppInfoReader();
	private ApiConsoleLocationProvider baseLocationProvider = new ApiConsoleLocationProvider();
	private TraitMappings traitMappings;

	private boolean ramlExpandEnabled = true;

	@Context
	private ServletContext servletContext;

	/**
	 * Returns content of the main page of the API Console.
	 * 
	 * If no "raml" query parameter is given, it will use the RAML defined in /api/api-listing.json file for rendering
	 * the API Console.
	 * 
	 * If the "raml" query parameter is given, it will it's value as the RAML for rendering the Console, provided
	 * it is within the context root of the API Console. If it is not in the context root it will render API Console's
	 * 404 error.
	 * 
	 * @param uriInfo access to request URI information
	 * @param ramlQueryParam query param with RAML file location
	 * @param externalUrlHeader optional header from proxy indicating external request
	 * @return in case no query parameter specified will redirect to the default RAML resource, otherwise will return
	 *         API Console's index.html.
	 * @throws IOException in case of problems reading the index file
	 */
	@GET
	@Path(INDEX)
	public Response getConsole(@Context final UriInfo uriInfo,
			@QueryParam(ApiConsoleLocationProvider.RAML_QUERY_PARAM) final String ramlQueryParam, //
			@HeaderParam(ExternalUrlHeaderUtil.HYBRIS_EXTERNAL_URL) final String externalUrlHeader) throws IOException
	{
		if (ramlQueryParam == null)
		{
			final URI uri = SecurityUtils.sanitizeRemoteUrl(baseLocationProvider.getApiConsoleUri(uriInfo, externalUrlHeader));
			return baseLocationProvider.processRedirect(uri);
		}
		else
		{
			final URL resource = getClass().getResource(STATIC_CONTENTS_SUBPACKAGE + "/" + INDEX);
			return Response.ok().entity(IOUtils.toByteArray(resource.openStream())).build();
		}
	}

	/**
	 * Redirects to the RAML resource path.
	 *
	 * @param uriInfo uri from jax-rx context to get the base uri
	 * @param externalUrlHeader the external header
	 * @return redirect to raml resource path
	 */
	@GET
	public final Response redirectFromRoot(@Context final UriInfo uriInfo,
			@HeaderParam(ExternalUrlHeaderUtil.HYBRIS_EXTERNAL_URL) final String externalUrlHeader)
	{
		final URI uri = UriBuilder
				.fromUri(SecurityUtils.sanitizeRemoteUrl(baseLocationProvider.getApiConsoleUri(uriInfo, externalUrlHeader)))
				.path(INDEX)
				.build();
		return baseLocationProvider.processRedirect(uri);
	}

	/**
	 * Return application info as JSON.
	 *
	 * @return Application info as JSON.
	 */
	@GET
	@Path("/app-version")
	@Produces(MediaType.APPLICATION_JSON)
	public AppInfo getAppVersion()
	{
		return appInfoReader.getAppVersion(servletContext);
	}

	/**
	 * Prepares and serves a RAML file which will be rendered by API Console. If the file cannot be found, the default
	 * RAML file will be loaded.
	 * 

* baseURI attribute in RAML file is modified to point at base URI of request or value specified in environment * variable. * * @param uriInfo access to request URI information * @param ramlResource path to RAML resource to return * @param externalUrlHeader external header * @param expand should the content be rewritten or not * @return response with status code 200 and content of specified RAML file, * or response with status code 404 if RAML resource not found * * @deprecated The ApiConsoleEndpoint should not be used to deliver RAML resources any more. Use * {@link com.sap.cloud.yaas.servicesdk.ramlrewriter.filter.RamlRewriterFilter} instead. */ @Deprecated @GET @Path(RamlFilePathProvider.RAML_RESOURCE_PATH + "{ramlResource: .*}") @Produces(MediaType.TEXT_PLAIN) public Response getRamlResource(@Context final UriInfo uriInfo, @PathParam("ramlResource") final String ramlResource, @HeaderParam(ExternalUrlHeaderUtil.HYBRIS_EXTERNAL_URL) final String externalUrlHeader, @QueryParam("expand") final Boolean expand) { LOG.trace("raml resource context : " + ramlResource); final URL pathUrl; try { pathUrl = getResourceUrl(ramlResource); } catch (final IllegalStateException e) { throw new NotFoundException("RAML Resource not found.", e); } final URI externalUrl = resolveExternalUrl(externalUrlHeader); final List mutators = getLineMutators( SecurityUtils.sanitizeRemoteUrl(uriInfo.getBaseUri()), ramlResource, SecurityUtils.sanitizeRemoteUrl(externalUrl)); return Response .ok() .entity(asRamlStreamingOutput(expand == null || expand ? ExpandingMode.FULL : ExpandingMode.NONE, pathUrl, mutators)) .build(); } /** * Prepares and serves the RAML file that has been specified in the api-listing.json of the /api folder. *

* baseURI attribute in RAML file is modified to point at base URI of request or value specified in environment * variable. * * @param uriInfo access to request URI information * @param externalUrlHeader external header * @param expand should the content be rewritten or not * @return response with status code 200 and content of specified RAML file, * or response with status code 404 if RAML resource not found * * @deprecated The ApiConsoleEndpoint should not be used to deliver RAML resources any more. Use * {@link com.sap.cloud.yaas.servicesdk.ramlrewriter.filter.RamlRewriterFilter} instead. */ @Deprecated @GET @Path(RamlFilePathProvider.RAML_RESOURCE_PATH) @Produces(MediaType.TEXT_PLAIN) public Response getDefaultRamlResource(@Context final UriInfo uriInfo, @HeaderParam(ExternalUrlHeaderUtil.HYBRIS_EXTERNAL_URL) final String externalUrlHeader, @QueryParam("expand") final Boolean expand) { return getRamlResource(uriInfo, baseLocationProvider.getRelativeRamlUri(), externalUrlHeader, expand); } /** * Gets URL for given resource. Override this if you would like to resolve the resource in different way than current * one. * * @param ramlResource given RAML resource relative path * * @return the URL pointing to requested RAML by its relative path */ protected URL getResourceUrl(final String ramlResource) { return baseLocationProvider.resolveRamlResource(getContextPath(), ramlResource); } /** * Gets absolute path of top allowed folder from api console. * * @return the full path to top level folder allowed to access via external requests. */ protected java.nio.file.Path getContextPath() { final URL rootPathUrl = getClass().getResource("/api"); if (rootPathUrl == null) { LOG.error("Cannot determine root folder, as no /api folder is present on the classpath"); throw new IllegalStateException("Cannot determine root folder, as no /api folder is present on the classpath"); } try { final URI rootPath = rootPathUrl.toURI(); if (LOG.isTraceEnabled()) { LOG.trace("Root context application path: " + rootPath); } return Paths.get(rootPath); } catch (final URISyntaxException e) { LOG.error("Cannot determine root folder", e); throw new IllegalStateException("Cannot determine root folder", e); } } protected RamlStreamingOutput asRamlStreamingOutput(final ExpandingMode expand, final URL resourceUrl, final List mutators) { return new RamlStreamingOutput(resourceUrl, mutators, expandEnabled(ramlExpandEnabled, expand) ? ExpandingMode.FULL : ExpandingMode.NONE); } @SuppressWarnings("deprecation") protected boolean expandEnabled(final boolean globalFlag, final ExpandingMode localFlag) { if (localFlag == null) { return globalFlag; } return !ExpandingMode.NONE.equals(localFlag) && !ExpandingMode.FALSE.equals(localFlag) && globalFlag; } protected List getLineMutators(final URI baseURI, final String ramlResource, final URI externalUrl) { final String listingPath = new RamlFilePathProvider().getApiBaseUri(ramlResource); return lineMutatorFactory.create(// resolveMappings(), // the urls and names of the traits to replace baseURI, // base url of the app externalUrl, // in case the request is external, appropriate parts of the url are replaced listingPath// the path defined in api-listing file for given raml file ); } private URI resolveExternalUrl(final String externalUrlHeader) { URI result = null; if (ExternalUrlHeaderUtil.isExternal(externalUrlHeader)) { result = ExternalUrlHeaderUtil.asExternalUri(externalUrlHeader); } return result != null ? result : null; } /** * This method resolves the list of traits which will be replaced with the oauth trait, together with the name and * url of oauth trait. One trait mapping contains the url path in !include, plus the name of the trait, for example * "https://api.yaas.io/patterns/v2/trait-yaas-aware.yaml" and "yaasAware". * * @return the trait mappings together with the URL to the lates oauth trait */ private TraitMappings resolveMappings() { if (traitMappings == null || traitMappings.getMappings().isEmpty()) { return getDefaultMappings(); } else { return traitMappings; } } /** * Serves static content of api console. * * @param directory name of directory * @param file name of file * @return entity with api console * @throws IOException in case of problems with reading the resource */ @GET @Path("/{directory}/{file}") public Response getStaticResource(@PathParam("directory") final String directory, @PathParam("file") final String file) throws IOException { StaticResourceUtils.assertPathSegmentIsSecure(directory); StaticResourceUtils.assertPathSegmentIsSecure(file); final String staticRersourcePath = STATIC_CONTENTS_SUBPACKAGE + "/" + directory + "/" + file; final URL resource = getClass().getResource(staticRersourcePath); final ResponseBuilder resultBuilder = resource != null ? Response.ok().entity(IOUtils.toByteArray(resource.openStream())) : Response.status(Response.Status.NOT_FOUND); resultBuilder.type(ResponseUtils.guessContentTypeHeader(file)); return resultBuilder.build(); } public void setBaseLocationProvider(final ApiConsoleLocationProvider baseLocationProvider) { this.baseLocationProvider = baseLocationProvider; } public void setTraitMappings(final TraitMappings traitMappings) { this.traitMappings = traitMappings; } public void setRamlExpand(final boolean enabled) { this.ramlExpandEnabled = enabled; } protected TraitMappings getDefaultMappings() { return TraitMappings.builder().withDefaultTraits().build(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy