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

com.sap.cds.adapter.odata.v4.CdsODataV4ServletFactory Maven / Gradle / Ivy

There is a newer version: 3.2.0
Show newest version
/**************************************************************************
 * (C) 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
 **************************************************************************/
package com.sap.cds.adapter.odata.v4;

import java.util.Objects;
import java.util.stream.Stream;

import com.sap.cds.adapter.ServletAdapterFactory;
import com.sap.cds.adapter.UrlResourcePath;
import com.sap.cds.reflect.CdsAction;
import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.reflect.CdsFunction;
import com.sap.cds.services.runtime.CdsRuntime;
import com.sap.cds.services.runtime.CdsRuntimeAware;
import com.sap.cds.services.utils.ODataUtils;
import com.sap.cds.services.utils.path.CdsResourcePath;
import com.sap.cds.services.utils.path.CdsServicePath;
import com.sap.cds.services.utils.path.UrlPathUtil;
import com.sap.cds.services.utils.path.UrlResourcePathBuilder;

public class CdsODataV4ServletFactory implements ServletAdapterFactory, CdsRuntimeAware {

	public static final String PROTOCOL_KEY = "odata-v4";

	private CdsRuntime runtime;

	@Override
	public void setCdsRuntime(CdsRuntime runtime) {
		this.runtime = runtime;
	}

	@Override
	public Object create() {
		return new CdsODataV4Servlet(runtime, getBasePath());
	}

	@Override
	public boolean isEnabled() {
		return runtime.getEnvironment().getCdsProperties().getOdataV4().getEndpoint().isEnabled();
	}

	@Override
	public String getBasePath() {
		return UrlPathUtil.normalizeBasePath(runtime.getEnvironment().getCdsProperties().getOdataV4().getEndpoint().getPath());
	}

	@Override
	public String[] getMappings() {
		Stream cdsServicePaths = CdsServicePath.servicePaths(runtime, PROTOCOL_KEY);
		return cdsServicePaths.map(servicePath -> UrlResourcePathBuilder.path(getBasePath(), servicePath.getPath()).recursive().build().getPath()).toArray(l -> new String[l]);
	}

	@Override
	public UrlResourcePath getServletPath() {

		final boolean openMetadataEndpoint = !runtime.getEnvironment().getCdsProperties().getSecurity().getAuthentication().isAuthenticateMetadataEndpoints();

		Stream cdsServicePaths = CdsServicePath.servicePaths(runtime, PROTOCOL_KEY);
		return UrlResourcePathBuilder.path(getBasePath())
				.recursive()
				.subPaths(
						cdsServicePaths.flatMap(cdsServicePath -> {

							boolean servicePublic = cdsServicePath.isPublic() && !cdsServicePath.subPaths().anyMatch(p -> !p.isPublic());
							return Stream.of(

									// Paths: /service/$metadata
									UrlResourcePathBuilder.path(cdsServicePath.getPath(), "$metadata").isPublic(openMetadataEndpoint || cdsServicePath.isPublic()).build(),

									// Path: /service/$batch
									UrlResourcePathBuilder.path(cdsServicePath.getPath(), "$batch").isPublic(servicePublic).build(),

									// Paths: /service/$all/**
									UrlResourcePathBuilder.path(cdsServicePath.getPath(), "$all").recursive().isPublic(servicePublic).build(),

									// Paths: /service/$crossjoin/**
									UrlResourcePathBuilder.path(cdsServicePath.getPath(), "$crossjoin").recursive().isPublic(servicePublic).build(),

									// Paths: /service and /service/entity/**
									UrlResourcePathBuilder.path(cdsServicePath.getPath())
									.isPublic(cdsServicePath.isPublic())
									.subPaths( cdsServicePath.subPaths().flatMap(cdsSubPath -> {

										if (cdsSubPath.hasType(CdsEntity.class)) {
											return Stream.of(
													// Path: /service/entity/**
													UrlResourcePathBuilder.path(ODataUtils.toODataName(cdsSubPath.getPath()))
													.recursive()
													.isPublic(cdsServicePath.isPublic() && cdsSubPath.isPublic())
													.publicEvents(cdsSubPath.publicEvents().map(UrlPathUtil::cdsEvent2HttpMethod).filter(Objects::nonNull))
													.subPaths( cdsSubPath.subPaths().flatMap(p -> { return actionOrFunction(cdsSubPath, p, cdsServicePath.isPublic() && cdsSubPath.isPublic());} ))
													.build(),

													// Path: /service/entity(*)/**
													UrlResourcePathBuilder.path( cdsSubPath.getPath() + "(*)" )
													.recursive()
													.isPublic(cdsServicePath.isPublic() && cdsSubPath.isPublic())
													.publicEvents(cdsSubPath.publicEvents().map(UrlPathUtil::cdsEvent2HttpMethod).filter(Objects::nonNull))
													.subPaths( cdsSubPath.subPaths().flatMap(p -> { return actionOrFunction(cdsSubPath, p, cdsServicePath.isPublic() && cdsSubPath.isPublic());}) )
													.build()
													);

										} else {
											return actionOrFunction(cdsServicePath, cdsSubPath, cdsServicePath.isPublic());
										}

									}) )
									.build(),

									// Paths: /service/
									UrlResourcePathBuilder.path(cdsServicePath.getPath(), "/")
									.isPublic(cdsServicePath.isPublic())
									.build()

									);
						})
						).build();
	}

	private static Stream actionOrFunction(CdsResourcePath parentPath, CdsResourcePath actionFunctionPath, boolean parentsArePublic) {

		if (actionFunctionPath.hasType(CdsAction.class) || actionFunctionPath.hasType(CdsFunction.class)) {

			String actionOrFunctionPath = actionFunctionPath.getPath();
			if (parentPath.hasType(CdsEntity.class)) {
				// bound action or function
				actionOrFunctionPath = parentPath.getCdsDefinition().getQualifier() + "." + actionFunctionPath.getPath();
			}

			String httpMethod = actionFunctionPath.hasType(CdsAction.class) ? UrlPathUtil.HttpMethod.POST.name() : UrlPathUtil.HttpMethod.GET.name();

			// function, function(*) resp. action and action(*)
			return Stream.of(
					UrlResourcePathBuilder.path(actionOrFunctionPath)
					.isPublic(false)
					.publicEvents( parentsArePublic && actionFunctionPath.isPublic() ? Stream.of(httpMethod) : Stream.empty() )
					.build(),

					UrlResourcePathBuilder.path(actionOrFunctionPath + "(*)")
					.isPublic(false)
					.publicEvents( parentsArePublic && actionFunctionPath.isPublic() ? Stream.of(httpMethod) : Stream.empty() )
					.build()
					);
		}

		return Stream.empty();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy