Skip to content

Commit

Permalink
feat(jans-config-api): agama patch endpoint (#2028)
Browse files Browse the repository at this point in the history
* bug(jans-config-api): fixed swagger format issue

* fix(jans-config-api): fixed due to couchbase clustter change

* feat(jans-config-api): new endpoint to get UmaResource based on associatedClient

* fix(jans-config-api): swagger spec fix for client attributes

* fix(jans-config-api): reverted the local test properties

* test(jans-config-api): commented test case

* feat(jans-config-api): scim config endpoint enhancment

* feat(jans-config-api): swagger and DTO change for new fields for scim config endpoint

* feat(jans-config-api): swagger and DTO change for new fields for scim config endpoint

* fix(jans-config-api): rectified endpoint url in swagger spec for uma resource

* feat(jans-config-api): agama endpoint fixes

* fix(jans-config-api): agama endpoint enhancements

* fix(jans-config-api): fixed swagger spec for Uma Resource delete

* fix(jans-config-api): agama endpoint enhancements

* fix(jans-config-api): agama endpoint enhancements

* fix(jans-config-api): agama endpoint enhancements

* fix(jans-config-api): agama endpoint enhancements

* fix(jans-config-api): agama endpoint enhancements

* feat(jans-config-api): agama patch endpoint

* feat(jans-config-api): agama patch endpoint

* feat(jans-config-api): agama patch endpoint
  • Loading branch information
pujavs authored Aug 4, 2022
1 parent 2c1414d commit 0b96a95
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,13 @@
import org.slf4j.Logger;

import com.github.fge.jsonpatch.JsonPatchException;
import com.github.fge.jsonpatch.JsonPatch;

@Path(ApiConstants.AGAMA)
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class AgamaResource extends ConfigBaseResource {

@Inject
Logger log;

@Inject
AgamaFlowService agamaFlowService;

Expand All @@ -58,8 +56,8 @@ public Response getFlows(@DefaultValue("") @QueryParam(value = ApiConstants.PATT
@DefaultValue(DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit,
@DefaultValue("false") @QueryParam(value = ApiConstants.INCLUDE_SOURCE) boolean includeSource) {

if (log.isDebugEnabled()) {
log.debug("Search Agama Flow with pattern:{}, sizeLimit:{}, includeSource:{}", escapeLog(pattern),
if (logger.isDebugEnabled()) {
logger.debug("Search Agama Flow with pattern:{}, sizeLimit:{}, includeSource:{}", escapeLog(pattern),
escapeLog(limit), escapeLog(includeSource));
}

Expand All @@ -80,12 +78,13 @@ public Response getFlows(@DefaultValue("") @QueryParam(value = ApiConstants.PATT
@Path(ApiConstants.QNAME_PATH)
public Response getFlowByName(@PathParam(ApiConstants.QNAME) @NotNull String flowName,
@DefaultValue("false") @QueryParam(value = ApiConstants.INCLUDE_SOURCE) boolean includeSource) {
if (log.isDebugEnabled()) {
log.debug("Search Agama with flowName:{}, includeSource:{}", escapeLog(flowName), escapeLog(includeSource));
if (logger.isDebugEnabled()) {
logger.debug("Search Agama with flowName:{}, includeSource:{}", escapeLog(flowName),
escapeLog(includeSource));
}

String decodedFlowName = getURLDecodedValue(flowName);
log.trace(" Agama Decoded flow name decodedFlowName:{}", decodedFlowName);
logger.trace(" Agama Decoded flow name decodedFlowName:{}", decodedFlowName);
Flow flow = findFlow(decodedFlowName, true, includeSource);

return Response.ok(flow).build();
Expand All @@ -95,22 +94,19 @@ public Response getFlowByName(@PathParam(ApiConstants.QNAME) @NotNull String flo
@ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS })
public Response createFlow(@Valid Flow flow)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
log.debug(" Flow to be added flow:{}, flow.getQName():{}, flow.getSource():{} ", flow, flow.getQname(),
logger.debug(" Flow to be added flow:{}, flow.getQName():{}, flow.getSource():{} ", flow, flow.getQname(),
flow.getSource());

// check if flow with same name already exists
Flow existingFlow = findFlow(flow.getQname(), false, false);
log.debug(" existingFlow:{}", existingFlow);
logger.debug(" existingFlow:{}", existingFlow);
if (existingFlow != null) {
thorwBadRequestException("Flow identified by name '" + flow.getQname() + "' already exist!");
}

// validate flow data
updateFlowDetails(flow, null);
validateAgamaFlowData(flow, true);
flow.setRevision(-1);
FlowMetadata flowMetadata = new FlowMetadata();
flowMetadata.setTimestamp(System.currentTimeMillis());
flow.setMetadata(flowMetadata);
agamaFlowService.addAgamaFlow(flow);

flow = findFlow(flow.getQname(), true, false);
Expand All @@ -123,14 +119,14 @@ public Response createFlow(@Valid Flow flow)
@ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS })
public Response createFlowFromFile(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @Valid String source)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
log.debug(" Flow to be created flowName:{}, source:{}", flowName, source);
logger.debug(" Flow to be created flowName:{}, source:{}", flowName, source);

String decodedFlowName = getURLDecodedValue(flowName);
log.trace(" Agama Decoded flow name for create is:{}", decodedFlowName);
logger.trace(" Agama Decoded flow name for create is:{}", decodedFlowName);

// check if flow with same name already exists
Flow existingFlow = findFlow(decodedFlowName, false, false);
log.debug(" existing-flow:{}", existingFlow);
logger.debug(" existing-flow:{}", existingFlow);
if (existingFlow != null) {
thorwBadRequestException("Flow identified by name '" + decodedFlowName + "' already exist!");
}
Expand All @@ -139,10 +135,7 @@ public Response createFlowFromFile(@PathParam(ApiConstants.QNAME) @NotNull Strin
flow.setQname(decodedFlowName);
flow.setSource(source);
flow.setEnabled(true);
flow.setRevision(-1);
FlowMetadata flowMetadata = new FlowMetadata();
flowMetadata.setTimestamp(System.currentTimeMillis());
flow.setMetadata(flowMetadata);
updateFlowDetails(flow, null);

// validate flow data
validateAgamaFlowData(flow, true);
Expand All @@ -157,25 +150,23 @@ public Response createFlowFromFile(@PathParam(ApiConstants.QNAME) @NotNull Strin
@ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS })
public Response updateFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @Valid Flow flow)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
log.debug(" Flow to update flowName:{}, flow:{}, flow.getQName():{}, flow.getSource():{} ", flowName, flow,
logger.debug(" Flow to update flowName:{}, flow:{}, flow.getQName():{}, flow.getSource():{} ", flowName, flow,
flow.getQname(), flow.getSource());

String decodedFlowName = getURLDecodedValue(flowName);
log.trace(" Agama Decoded flow name for update is:{}", decodedFlowName);
logger.trace(" Agama Decoded flow name for update is:{}", decodedFlowName);

// check if flow exists
Flow existingFlow = findFlow(decodedFlowName, true, false);

// set flow data
flow.setQname(decodedFlowName);
log.trace("Flow revision check - flow.getRevision():{}, existingFlow.getRevision():{}", flow.getRevision(),
existingFlow.getRevision());
getRevision(flow, existingFlow);
log.debug("Flow revision after update - flow.getRevision():{}", flow.getRevision());
updateFlowDetails(flow, existingFlow);
logger.debug("Flow revision after update - flow.getRevision():{}", flow.getRevision());

// validate flow data
validateAgamaFlowData(flow, false);
log.debug("Updating flow after validation");
logger.debug("Updating flow after validation");
agamaFlowService.updateFlow(flow);

flow = findFlow(decodedFlowName, true, false);
Expand All @@ -188,24 +179,24 @@ public Response updateFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowNa
@ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS })
public Response updateFlowFromFile(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @Valid String source)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
log.debug(" Flow to be updated flowName:{}, source:{}", flowName, source);
logger.debug(" Flow to be updated flowName:{}, source:{}", flowName, source);

String decodedFlowName = getURLDecodedValue(flowName);
log.trace(" Agama flow name for update is:{}", decodedFlowName);
logger.trace(" Agama flow name for update is:{}", decodedFlowName);

// check if flow with same name already exists
Flow existingFlow = findFlow(decodedFlowName, false, false);
log.debug(" Agama existingFlow:{}", existingFlow);
// check if flow with same name exists
Flow existingFlow = findFlow(decodedFlowName, true, false);
logger.debug(" Agama existingFlow:{}", existingFlow);

// Update source and revision
if (existingFlow != null) {
existingFlow.setSource(source);

getRevision(existingFlow, existingFlow);
updateFlowDetails(existingFlow, existingFlow);

// validate flow data
validateAgamaFlowData(existingFlow, false);
log.debug("Update flow after validation");
logger.debug("Update flow after validation");
agamaFlowService.updateFlow(existingFlow);

existingFlow = findFlow(existingFlow.getQname(), true, false);
Expand All @@ -217,26 +208,28 @@ public Response updateFlowFromFile(@PathParam(ApiConstants.QNAME) @NotNull Strin
@Consumes(MediaType.APPLICATION_JSON_PATCH_JSON)
@Path(ApiConstants.QNAME_PATH)
@ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS })
public Response patchFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @NotNull String pathString)
public Response patchFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @NotNull JsonPatch jsonPatch)
throws JsonPatchException, IOException, NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (logger.isDebugEnabled()) {
logger.debug("Flow details to be patched - flowName:{}, pathString:{}", escapeLog(flowName),
escapeLog(pathString));
logger.debug("Flow details to be patched - flowName:{}, jsonPatch:{}", escapeLog(flowName),
escapeLog(jsonPatch));
}

String decodedFlowName = getURLDecodedValue(flowName);
log.trace(" Flow name for update is:{}", decodedFlowName);
logger.debug(" Flow to be patched is name:{}", decodedFlowName);

// check if flow exists
Flow existingFlow = findFlow(decodedFlowName, false, true);
log.debug(" existingFlow:{}", existingFlow);
logger.debug(" Flow to be patched:{}", existingFlow);

existingFlow = Jackson.applyPatch(pathString, existingFlow);
getRevision(existingFlow, existingFlow);
existingFlow = Jackson.applyJsonPatch(jsonPatch, existingFlow);
logger.debug(" After patch flow:{}", existingFlow);
updateFlowDetails(existingFlow, existingFlow);

// validate flow data
validateAgamaFlowData(existingFlow, false);
log.debug("Updating flow after validation");
logger.debug("Updating flow after validation");
agamaFlowService.updateFlow(existingFlow);
return Response.ok(existingFlow).build();
}
Expand All @@ -245,9 +238,9 @@ public Response patchFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowNam
@Path(ApiConstants.QNAME_PATH)
@ProtectedApi(scopes = { ApiAccessConstants.AGAMA_DELETE_ACCESS })
public Response deleteAttribute(@PathParam(ApiConstants.QNAME) @NotNull String flowName) {
log.debug(" Flow to delete - flowName:{}", flowName);
logger.debug(" Flow to delete - flowName:{}", flowName);
String decodedFlowName = getURLDecodedValue(flowName);
log.trace(" Agama Decoded flow name is:{}", decodedFlowName);
logger.trace(" Agama Decoded flow name is:{}", decodedFlowName);

// check if flow exists
Flow flow = findFlow(decodedFlowName, true, false);
Expand All @@ -262,31 +255,33 @@ private Flow findFlow(String flowName, boolean throwError, boolean includeSource
flow = agamaFlowService.getFlowByName(flowName);

// filter values
List<Flow> flows = Arrays.asList(flow);
getAgamaFlowDetails(flows, includeSource);
if (flows != null && !flows.isEmpty()) {
flow = flows.get(0);
if (flow != null) {
List<Flow> flows = Arrays.asList(flow);
getAgamaFlowDetails(flows, includeSource);
if (flows != null && !flows.isEmpty()) {
flow = flows.get(0);
}
}
} catch (EntryPersistenceException e) {
log.error("No flow found with the name:{} ", flowName);
logger.error("No flow found with the name:{} ", flowName);
if (throwError) {
throw new NotFoundException(getNotFoundError("Flow - " + flowName + "!!!"));
throw new NotFoundException(getNotFoundError("Flow - '" + flowName + "'"));
}
}
return flow;
}

private void validateAgamaFlowData(Flow flow, boolean checkNonMandatoryFields)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
log.debug(" Validate Agama Flow data - flow:{}, checkNonMandatoryFields:{}", flow, checkNonMandatoryFields);
logger.debug(" Validate Agama Flow data - flow:{}, checkNonMandatoryFields:{}", flow, checkNonMandatoryFields);
if (flow == null) {
return;
}
log.debug("Agama Flow to be added flow:{}, flow.getQname():{}, flow.getSource():{} ", flow, flow.getQname(),
logger.debug("Agama Flow to be added flow:{}, flow.getQname():{}, flow.getSource():{} ", flow, flow.getQname(),
flow.getSource());

String validateMsg = agamaFlowService.validateFlowFields(flow, checkNonMandatoryFields);
log.debug("Agama Flow to be validation msg:{} ", validateMsg);
logger.debug("Agama Flow to be validation msg:{} ", validateMsg);
if (StringUtils.isNotBlank(validateMsg)) {
thorwBadRequestException(validateMsg);
}
Expand All @@ -296,71 +291,105 @@ private void validateAgamaFlowData(Flow flow, boolean checkNonMandatoryFields)
}

private void validateSyntax(Flow flow) {
log.debug("Validate Flow Source Syntax - flow:{}", flow);
logger.debug("Validate Flow Source Syntax - flow:{}", flow);
if (flow == null) {
return;
}
// validate syntax
try {
Transpiler.runSyntaxCheck(flow.getQname(), flow.getSource());
} catch (SyntaxException se) {
log.error("Transpiler syntax check error", se);
logger.error("Transpiler syntax check error", se);
try {
log.debug("Throwing BadRequestException 400 :{} ", Jackson.asPrettyJson(se));
thorwBadRequestException(Jackson.asJson(se));
logger.debug("Throwing BadRequestException 400 :{} ", Jackson.asPrettyJson(se));
thorwBadRequestException(se);
} catch (IOException io) {
log.error("Agama Flow Transpiler syntax error parsing error", io);
logger.error("Agama Flow Transpiler syntax error parsing error", io);
thorwBadRequestException("Transpiler syntax check error" + se);
}
} catch (TranspilerException te) {
log.error("Agama Flow transpiler exception", te);
thorwBadRequestException(te.toString());
logger.error("Agama Flow transpiler exception", te);
thorwBadRequestException(te);
}
}

private String getURLDecodedValue(String pathParam) {
log.debug(" Decode pathParam():{} ", pathParam);
logger.debug(" Decode pathParam():{} ", pathParam);
try {
return URLDecoder.decode(pathParam, UTF_8.name());
} catch (UnsupportedEncodingException uee) {
log.error("Agama Flow error while URL decoding pathParam:{}, is:{}", pathParam, uee);
logger.error("Agama Flow error while URL decoding pathParam:{}, is:{}", pathParam, uee);
}
return pathParam;
}

private Flow getRevision(Flow flow, Flow existingFlow) {
log.debug("Flow revision check - flow:{}, existingFlow:{}", flow, existingFlow);
private Flow updateFlowDetails(Flow flow, Flow existingFlow) {
logger.debug("Update Flow details - flow:{}, existingFlow:{}", flow, existingFlow);

updateRevision(flow, existingFlow);
updateMetadata(flow);
return flow;
}

private Flow updateRevision(Flow flow, Flow existingFlow) {
logger.debug("Flow revision check - flow:{}, existingFlow:{}", flow, existingFlow);

if (flow == null) {
return flow;
}

if (flow == null || existingFlow == null) {
if (existingFlow == null) {
flow.setRevision(-1);
return flow;
}

log.debug("Flow revision check - flow.getRevision():{}, existingFlow.getRevision():{}", flow.getRevision(),
existingFlow.getRevision());
logger.trace("Flow revision before update - flow.getRevision():{}, existingFlow.getRevision():{}",
flow.getRevision(), existingFlow.getRevision());

if (flow.getSource() != null && flow.getRevision() == 0) {
if (existingFlow.getRevision() == 0 || existingFlow.getRevision() == -1) {
if (flow.getSource() != null && (flow.getRevision() <= 0 || flow.getRevision() == existingFlow.getRevision())) {
if (existingFlow.getRevision() <= 0) {
flow.setRevision(1);
} else {
flow.setRevision(existingFlow.getRevision() + 1);
}
}
log.debug("Final flow revision to be updated to - flow.getRevision():{}", flow.getRevision());
logger.trace("Flow revision after update - flow.getRevision():{}", flow.getRevision());
return flow;
}

private Flow updateMetadata(Flow flow) {
logger.debug("Update Flow Metadata - flow:{}", flow);

if (flow == null) {
return flow;
}

FlowMetadata flowMetadata = flow.getMetadata();
if (flowMetadata == null) {
flowMetadata = new FlowMetadata();
}

logger.trace("Flow Metadata Timestamp before update - flowMetadata.getTimestamp():{}",
flowMetadata.getTimestamp());
flowMetadata.setTimestamp(System.currentTimeMillis());
flow.setMetadata(flowMetadata);

logger.trace("Flow Metadata Timestamp after update - flowMetadata.getTimestamp():{}",
flowMetadata.getTimestamp());
return flow;
}

private List<Flow> getAgamaFlowDetails(List<Flow> flows, boolean includeSource) {

log.debug("Flow data filter - flows:{}, includeSource:{}", flows, includeSource);
logger.debug("Flow data filter - flows:{}, includeSource:{}", flows, includeSource);
if (flows == null || flows.isEmpty()) {
return flows;
}

for (Flow flow : flows) {

flow.setTranspiled(null);
flow.setTransHash(null);

if (!includeSource) {
flow.setSource(null);
}
Expand Down
Loading

0 comments on commit 0b96a95

Please sign in to comment.