All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sap.cloud.yaas.servicesdk.apiconsole.web.ApiConsoleEndpoint Maven / Gradle / Ivy
/*
* © 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();
}
}