com.sap.cds.feature.ucl.adapter.UclServlet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cds-feature-ucl Show documentation
Show all versions of cds-feature-ucl Show documentation
Unified Customer Landscape feature for CDS Services Java
The newest version!
package com.sap.cds.feature.ucl.adapter;
import com.sap.cds.impl.parser.JsonParser;
import com.sap.cds.impl.parser.token.Jsonizer;
import com.sap.cds.services.ErrorStatuses;
import com.sap.cds.services.ServiceException;
import com.sap.cds.feature.ucl.services.SpiiContext;
import com.sap.cds.feature.ucl.services.SpiiResult;
import com.sap.cds.feature.ucl.services.UclService;
import com.sap.cds.services.runtime.CdsRuntime;
import com.sap.cds.services.utils.ErrorStatusException;
import com.sap.cds.services.utils.StringUtils;
import com.sap.cds.services.utils.cert.CertValidator;
import com.sap.cds.services.utils.cert.UclAuthUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.function.Predicate;
import static com.sap.cds.services.utils.cert.UclAuthUtils.checkAuthorization;
public class UclServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(UclServlet.class);
private static final String METHOD_PATCH = "PATCH";
private final UclService uclService;
private final CdsRuntime runtime;
private final CertValidator certValidator;
public UclServlet(CdsRuntime runtime) {
this.runtime = runtime;
this.uclService = runtime.getServiceCatalog().getService(UclService.class, UclService.DEFAULT_NAME);
this.certValidator = UclAuthUtils.createCertValidator(runtime);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// by default, HttpServlet does not support PATCH method
String method = req.getMethod();
if (method.equals(METHOD_PATCH)) {
this.doPatch(req, resp);
} else {
super.service(req, resp);
}
}
/*
* Endpoint for formation notification: PATCH https:////ucl/spii/v1/tenantMappings/{tenantId}.
*/
@SuppressWarnings("unchecked")
protected void doPatch(HttpServletRequest req, HttpServletResponse res) {
logger.debug("Received call in Spii tenant mapping");
processRequest(req, res, p -> !p.isEmpty(), () -> {
String tenantId = getTenantId(req);
SpiiRequest spiiRequest = SpiiRequest.of((Map)JsonParser.map(new InputStreamReader(req.getInputStream())));
SpiiContext ctx = spiiRequest.getContext();
logger.info("Performing operation '{}' for formation '{}' and tenant '{}'", ctx.getOperation(), ctx.getUclFormationName(), tenantId);
String resultState = "CREATE_READY";
Map resultConfiguration = new HashMap<>();
String operation = ctx.getOperation();
//TODO: Use async SPII API once certificate is provided via OSB
if("assign".equals(operation)) {
try {
SpiiResult result = this.uclService.assign(tenantId, spiiRequest.getContext(), spiiRequest.getReceiverTenant(), spiiRequest.getAssignedTenant());
if (result.getReady()) {
resultState = "CREATE_READY";
} else {
resultState = "CONFIG_PENDING";
}
resultConfiguration = result.getConfiguration();
} catch (ServiceException e) {
logger.error("Error while processing operation '{}' for formation '{}' and '{}'", ctx.getOperation(), ctx.getUclFormationName(), tenantId, e);
resultState = "CREATE_ERROR";
}
} else if ("unassign".equals(operation)) {
try {
this.uclService.unassign(tenantId, spiiRequest.getContext(), spiiRequest.getReceiverTenant(), spiiRequest.getAssignedTenant());
resultState = "DELETE_READY";
} catch(ServiceException e) {
logger.error("Error while processing operation '{}' for formation '{}' and '{}'", ctx.getOperation(), ctx.getUclFormationName(), tenantId, e);
resultState = "DELETE_ERROR";
}
}
res.setStatus(HttpServletResponse.SC_OK); // not SC_CREATED!
setContentType(res, ContentType.APPLICATION_JSON);
Map response = new HashMap<>();
response.put("state", resultState);
response.put("configuration", resultConfiguration);
Jsonizer.write(res.getWriter(), response);
});
}
private static String getTenantId(HttpServletRequest req) {
// gets the app_tid from the request path
String[] segments = req.getPathInfo().split("/");
if (segments.length < 2 || StringUtils.isEmpty(segments[1])) {
throw new ErrorStatusException(ErrorStatuses.BAD_REQUEST);
}
return segments[1];
}
private static void setContentType(HttpServletResponse resp, ContentType contType) {
resp.setContentType(contType.getMimeType());
resp.setCharacterEncoding(contType.getCharset().toString());
}
@FunctionalInterface
private interface Processor {
void process() throws IOException;
}
private static void handleException(HttpServletResponse res, Locale locale, ServiceException e) {
if (e.getErrorStatus().getHttpStatus() >= 500 && e.getErrorStatus().getHttpStatus() < 600) {
logger.error("Unexpected error", e);
} else {
logger.debug("Service exception thrown", e);
}
res.setStatus(e.getErrorStatus().getHttpStatus());
try {
String message = e.getLocalizedMessage(locale);
if (message != null) {
try (PrintWriter writer = res.getWriter()) {
writer.write(message);
}
}
} catch (IOException e1) {
logger.error("Failed to write error message to response", e1);
}
}
private void processRequest(HttpServletRequest req, HttpServletResponse res, Predicate pathMatcher, Processor processor) {
if (pathMatcher.test(req.getPathInfo())) {
try {
checkAuthorization(certValidator, runtime);
} catch (ServiceException e) {
handleException(res, null, e);
return;
} catch (Throwable t) {
logger.error("Unexpected error", t);
res.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
return;
}
runtime.requestContext().systemUserProvider()
.run(requestContext -> {
try {
processor.process();
} catch (ServiceException e) {
handleException(res, requestContext.getParameterInfo().getLocale(), e);
} catch (Throwable t) {
logger.error("Unexpected error", t);
res.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
}
});
} else {
res.setStatus(HttpStatus.SC_NOT_FOUND);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy