com.sap.cds.adapter.odata.v2.CdsODataV2ServiceFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cds-adapter-odata-v2 Show documentation
Show all versions of cds-adapter-odata-v2 Show documentation
OData V2 adapter for CDS Services Java
/**************************************************************************
* (C) 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
**************************************************************************/
package com.sap.cds.adapter.odata.v2;
import java.util.Map;
import java.util.Optional;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.olingo.odata2.api.ODataCallback;
import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.ODataServiceFactory;
import org.apache.olingo.odata2.api.exception.ODataException;
import org.apache.olingo.odata2.api.processor.ODataContext;
import org.apache.olingo.odata2.api.uri.PathInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sap.cds.adapter.odata.v2.metadata.MetadataInfo;
import com.sap.cds.adapter.odata.v2.metadata.model.AbstractEdmxProviderAccessor;
import com.sap.cds.adapter.odata.v2.processors.ErrorCallback;
import com.sap.cds.adapter.odata.v2.processors.OlingoProcessor;
import com.sap.cds.adapter.odata.v2.query.SystemQueryLoader;
import com.sap.cds.services.ErrorStatuses;
import com.sap.cds.services.ServiceException;
import com.sap.cds.services.cds.ApplicationService;
import com.sap.cds.services.runtime.CdsRuntime;
import com.sap.cds.services.utils.CdsErrorStatuses;
import com.sap.cds.services.utils.ErrorStatusException;
import com.sap.cds.services.utils.ODataUtils;
import com.sap.cds.services.utils.StringUtils;
import com.sap.cds.services.utils.path.CdsServicePath;
public class CdsODataV2ServiceFactory extends ODataServiceFactory {
private static final Logger logger = LoggerFactory.getLogger(CdsODataV2ServiceFactory.class);
private static final String PATHINFO = "~pathInfo";
private static final String UNEXPECTED_ERROR_MESSAGE = "An unexpected error occurred during servlet processing";
private final CdsRuntime runtime;
private final Map servicePaths;
public CdsODataV2ServiceFactory(CdsRuntime runtime) {
this.runtime = runtime;
this.servicePaths = CdsServicePath.basePaths(runtime, CdsODataV2ServletFactory.PROTOCOL_KEY);
// initialize metadata provider and caches
AbstractEdmxProviderAccessor.initialize(runtime);
SystemQueryLoader.initialize(runtime);
}
@Override
public ODataService createService(ODataContext context) throws ODataException {
HttpServletRequest request = (HttpServletRequest) context.getParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT);
CdsRequestGlobals requestGlobals = (CdsRequestGlobals) request.getAttribute(CdsODataV2Servlet.ATTRIBUTE_REQUEST_GLOBALS);
try {
PathInfo path = (PathInfo) context.getParameter(PATHINFO);
String pathInfo = path.getRequestUri().getPath();
if (pathInfo == null) {
throw new ErrorStatusException(CdsErrorStatuses.INVALID_URI_RESOURCE);
}
MutablePair serviceInfo = extractServiceInfo(request.getPathInfo(), servicePaths);
ApplicationService applicationService = serviceInfo.getLeft();
String serviceName = applicationService.getDefinition().getQualifiedName();
requestGlobals.setApplicationService(applicationService);
applicationService.getDefinition().entities().forEach(entity -> {
String cdsName = entity.getName();
String edmName = ODataUtils.toODataName(cdsName);
if (!edmName.equals(cdsName)) {
String key = entity.getQualifier() + "." + edmName;
String value = entity.getQualifier() + "." + cdsName;
requestGlobals.getCdsEntityNames().put(key, value);
}
});
MetadataInfo metadataInfo = AbstractEdmxProviderAccessor.getInstance().getMetadataInfo(serviceName);
if (metadataInfo.getEdmxMetadataProvider() == null) {
throw new ErrorStatusException(CdsErrorStatuses.SERVICE_NOT_FOUND, serviceName);
}
return createODataSingleProcessorService(metadataInfo.getEdmxMetadataProvider(), new OlingoProcessor(metadataInfo, requestGlobals));
} catch (ServiceException e) {
int httpStatus = e.getErrorStatus().getHttpStatus();
if(httpStatus >= 500 && httpStatus < 600) {
logger.error(UNEXPECTED_ERROR_MESSAGE, e);
} else {
logger.debug(UNEXPECTED_ERROR_MESSAGE, e);
}
} catch (Exception e) { // NOSONAR
logger.error(UNEXPECTED_ERROR_MESSAGE, e);
}
return null;
}
/**
* Extracts the service name from the given url path.
*
* Common schema of an odata request:
http://host:port/path/SampleService.svc/Categories(1)/Products?$top=2&$orderby=Name
\______________________________________/\____________________/ \__________________/
| | |
service root URL resource path query options
\________________________________________/
|
pathInfo
*/
private MutablePair extractServiceInfo(String pathInfo, Map servicePaths) {
if(pathInfo.trim().isEmpty()) {
throw new ErrorStatusException(ErrorStatuses.NOT_FOUND);
}
Optional servicePathKey = getServicePath(pathInfo);
if(servicePathKey.isPresent()) {
// service should have a path derived from the model
String servicePath = servicePathKey.get();
ApplicationService service = servicePaths.get(servicePath);
if (service != null) {
return MutablePair.of(service, servicePath);
}
}
throw new ErrorStatusException(CdsErrorStatuses.SERVICE_NOT_FOUND, pathInfo);
}
/**
* Returns an {@link Optional} describing the service path matching the given path info
* most accurately.
*
* @param pathInfo the path info to find the service path for
* @return the service path optional
*/
public Optional getServicePath(String pathInfo) {
String path = StringUtils.trim(pathInfo.trim(), '/');
return servicePaths.keySet().stream()
// sort from longest path to shortest
.sorted((a, b) -> -1 * Integer.compare(a.length(), b.length()))
// find the most accurate match
.filter(p -> path.startsWith(p)).findFirst();
}
@SuppressWarnings("unchecked")
@Override
public T getCallback(final Class callbackInterface) {
return (T) (callbackInterface.isAssignableFrom(ErrorCallback.class) ?
new ErrorCallback(runtime) : super.getCallback(callbackInterface));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy