From f9b7362037f86e8dba6cf7430a4bdc8bfa79e509 Mon Sep 17 00:00:00 2001 From: Afira Zahari Date: Tue, 14 Dec 2021 14:39:53 +0000 Subject: [PATCH] v1.4.0 public release --- README.md | 2 +- .../com/i2group/nypd/ConnectorController.java | 219 ++++++++++++++++++ .../src/main/resources/analyst-config.json | 141 +++++++++++ .../src/main/resources/global-config.json | 6 + .../src/main/resources/other-config.json | 65 ++++++ 5 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 connector/user-config/override/nypd-connector/src/main/java/com/i2group/nypd/ConnectorController.java create mode 100644 connector/user-config/override/nypd-connector/src/main/resources/analyst-config.json create mode 100644 connector/user-config/override/nypd-connector/src/main/resources/global-config.json create mode 100644 connector/user-config/override/nypd-connector/src/main/resources/other-config.json diff --git a/README.md b/README.md index 0f19f11..18d44f6 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ search all the data in an external source, or a subset of the data that satisfies a set of specified conditions. The connectors also perform server-side validation to prohibit invalid requests. -- [Read the documentation](http://ibm-i2.github.io/analyze-connect) +- [Read the documentation](https://ibm-i2.github.io/analyze-connect) - [Download a ZIP archive of this repository](https://github.com/IBM-i2/Analyze-Connect/releases) You can raise issues and questions about the example connectors for the i2 diff --git a/connector/user-config/override/nypd-connector/src/main/java/com/i2group/nypd/ConnectorController.java b/connector/user-config/override/nypd-connector/src/main/java/com/i2group/nypd/ConnectorController.java new file mode 100644 index 0000000..dc6a8d7 --- /dev/null +++ b/connector/user-config/override/nypd-connector/src/main/java/com/i2group/nypd/ConnectorController.java @@ -0,0 +1,219 @@ +/******************************************************************************** +# * Licensed Materials - Property of IBM +# * (C) Copyright IBM Corporation 2021. All Rights Reserved +# * +# * This program and the accompanying materials are made available under the +# * terms of the Eclipse Public License 2.0 which is available at +# * http://www.eclipse.org/legal/epl-2.0. +# * +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# * +# ********************************************************************************/ + +package com.i2group.nypd; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.i2group.nypd.rest.transport.ConnectorResponse; +import com.i2group.nypd.rest.transport.ValidationResponse; +import com.i2group.nypd.rest.transport.request.ConnectorRequest; +import com.i2group.nypd.rest.transport.request.RequestCondition; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +import java.io.IOException; +import java.util.Base64; +import java.util.List; + +import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE; +import static org.springframework.util.MimeTypeUtils.APPLICATION_XML_VALUE; + +/** Defines endpoints used by i2 Analyze to acquire data */ +@RestController +public class ConnectorController { + + private final ExternalConnectorDataService connectorDataService; + @Value("classpath:global-config.json") + private Resource globalConfigResource; + + @Value("classpath:analyst-config.json") + private Resource analystConfigResource; + + @Value("classpath:other-config.json") + private Resource otherConfigResource; + + @Value("classpath:nypd-complaint-data-schema.xml") + private Resource schemaResource; + @Value("classpath:nypd-complaint-data-schema-charting-schemes.xml") + private Resource chartingSchemesResource; + + @Autowired + private ObjectMapper objectMapper; + + /** + * Creates an instance of the ExternalConnectorDataService used to complete acquires. + * + * @param connectorDataService The class containing operations which perform the operation defined + * by the various services. + */ + public ConnectorController(ExternalConnectorDataService connectorDataService) { + this.connectorDataService = connectorDataService; + } + + /** + * Defines the /config endpoint which provides global connector configuration data. + * + * @return The global configuration. + */ + @RequestMapping(method = RequestMethod.GET, value = "/config", produces = APPLICATION_JSON_VALUE) + public Resource config() { + return globalConfigResource; + } + + /** + * Defines the /userconfig endpoint, which provides user-specific connector configuration data. + * + * @return The user-specific configuration. + */ + @RequestMapping(method = RequestMethod.GET, value = "/userconfig", produces = APPLICATION_JSON_VALUE) + public Resource userConfig(@RequestHeader(value = "I2-Principal", required = false) String principalName, + @RequestHeader(value = "I2-Display-Name", required = false) String displayName, + @RequestHeader(value = "I2-User-Groups", required = false) String userGroups, + @RequestHeader(value = "I2-Security-Permissions", required = false) String securityPermissions, + @RequestHeader(value = "I2-Command-Access-Permissions", required = false) String cacPermissions) { + + final List decodedGroups = decode(userGroups, List.class); + if (decodedGroups != null && decodedGroups.contains("Analyst")) { + System.out.println(principalName + " is an Analyst"); + return analystConfigResource; + } else { + System.out.println(principalName + " is not an Analyst"); + return otherConfigResource; + } + } + + private T decode(String header, Class type) { + if (header == null) { + return null; + } + final byte[] decoded = Base64.getDecoder().decode(header); + try { + return objectMapper.readValue(decoded, type); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Defines the endpoint used to retrieve the connector schema. + * + * @return The connector schema. + */ + @RequestMapping(method = RequestMethod.GET, value = "/schema", produces = APPLICATION_XML_VALUE) + public Resource schema() { + return schemaResource; + } + + /** + * Defines the endpoint used to retrieve the connector charting schemes. + * + * @return The connector charting schemes. + */ + @RequestMapping(method = RequestMethod.GET, value = "/charting-schemes", + produces = APPLICATION_XML_VALUE) + public Resource chartingSchemes() { + return chartingSchemesResource; + } + + /** + * Defines the /all endpoint which returns all entities and links. + * + * @return The response containing all entities and links. + */ + @RequestMapping(method = RequestMethod.POST, value = "/all", consumes = APPLICATION_JSON_VALUE, + produces = APPLICATION_JSON_VALUE) + public ConnectorResponse allService() { + return connectorDataService.retrieveAll(); + } + + /** + * Defines the /search endpoint which retrieves entities and links based on conditions. + * + * @param request The request containing the payload. + * @return The resulting entities and links after a conditional search. + */ + @RequestMapping(method = RequestMethod.POST, value = "/search", consumes = APPLICATION_JSON_VALUE, + produces = APPLICATION_JSON_VALUE) + public ConnectorResponse searchService(@Valid @RequestBody ConnectorRequest request) { + return connectorDataService.search(request.payload.conditions); + } + + /** + * Defines the /search/validate endpoint which validates the condition inputs. + * + * @param request The request containing the payload. + * @return A response containing an error message or nothing. + */ + @RequestMapping(method = RequestMethod.POST, value = "/search/validate", + consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + public ValidationResponse searchValidate(@Valid @RequestBody ConnectorRequest request) { + final ValidationResponse validationResponse = new ValidationResponse(); + final List conditions = request.payload.conditions; + final boolean conditionPresent = conditions.stream() + .anyMatch(condition -> condition.value != null); + + if (!conditionPresent) { + validationResponse.errorMessage = "At least one search field should have a specified value."; + } + return validationResponse; + } + + /** + * Defines the /find-like-this-complaint endpoint which finds complaints similar to a selected + * complaint. + * + * @param request The request containing the payload. + * @return The entities found which are similar to the selected complaint. + */ + @RequestMapping(method = RequestMethod.POST, value = "/find-like-this-complaint", + consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + public ConnectorResponse findLikeThisComplaintService( + @Valid @RequestBody ConnectorRequest request) { + return connectorDataService.findLikeThisComplaint(request.payload.seeds); + } + + /** + * Defines the /expand endpoint which finds entities and links connected to selected entities. + * + * @param request The request containing the payload. + * @return The resulting entities and links connected to the selected entities. + */ + @RequestMapping(method = RequestMethod.POST, value = "/expand", consumes = APPLICATION_JSON_VALUE, + produces = APPLICATION_JSON_VALUE) + public ConnectorResponse expandService(@Valid @RequestBody ConnectorRequest request) { + return connectorDataService.expand(request.payload.seeds); + } + + /** + * Defines the /expand-with-conditions endpoint which finds entities and links connected to + * selected entities and also satisfies passed conditions. + * + * @param request The request containing the payload. + * @return The resulting entities and links which meet the requirements. + */ + @RequestMapping(method = RequestMethod.POST, value = "/expand-with-conditions", + consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + public ConnectorResponse expandWithConditionsService( + @Valid @RequestBody ConnectorRequest request) { + return connectorDataService.expandWithConditions(request.payload); + } +} diff --git a/connector/user-config/override/nypd-connector/src/main/resources/analyst-config.json b/connector/user-config/override/nypd-connector/src/main/resources/analyst-config.json new file mode 100644 index 0000000..8e1a9a7 --- /dev/null +++ b/connector/user-config/override/nypd-connector/src/main/resources/analyst-config.json @@ -0,0 +1,141 @@ +{ + "defaultValues": { + "timeZoneId": "Europe/London", + "resultIdsPersistent": true + }, + "services": [ + { + "id": "nypd-service", + "name": "NYPD Connector: Get All", + "description": "A service which retrieves all data", + "clientConfigType": "NONE", + "acquireUrl": "/all" + }, + { + "id": "nypd-search-service", + "name": "NYPD Connector: Search", + "description": "A service for conditional searches", + "clientConfigType": "FORM", + "clientConfigId": "searchForm", + "acquireUrl": "/search", + "validateUrl": "/search/validate" + }, + { + "id": "nypd-find-like-this-complaint-service", + "name": "NYPD Connector: Find like this Complaint", + "description": "A service which finds a similar complaint", + "clientConfigType": "NONE", + "acquireUrl": "/find-like-this-complaint", + "seedConstraints": { + "min": 1, + "max": 1, + "seedTypes": { + "allowedTypes": "ENTITY", + "itemTypes": [ + { + "id": "ET1", + "min": 1, + "max": 1 + } + ] + } + } + }, + { + "id": "nypd-expand-service", + "name": "NYPD Connector: Expand", + "description": "A service which executes an Expand operation on a seed", + "clientConfigType": "NONE", + "acquireUrl": "/expand", + "seedConstraints": { + "min": 1, + "max": 1, + "seedTypes": { + "allowedTypes": "ENTITY", + "itemTypes": [ + { + "id": "ET1" + }, + { + "id": "ET2" + } + ] + } + } + }, + { + "id": "nypd-expand-with-conditions", + "name": "NYPD Connector: Expand with Conditions", + "description": "A service which executes an Expand operation on a seed with conditions", + "clientConfigType": "FORM", + "clientConfigId": "searchForm", + "acquireUrl": "/expand-with-conditions", + "seedConstraints": { + "min": 1, + "max": 1, + "seedTypes": { + "allowedTypes": "ENTITY", + "itemTypes": [ + { + "id": "ET1" + }, + { + "id": "ET2" + } + ] + } + } + } + ], + "clientConfigs": [ + { + "id": "searchForm", + "config": { + "sections": [ + { + "conditions": [ + { + "id": "boro_nm", + "label": "Borough Name", + "logicalType": "SELECTED_FROM", + "possibleValues": [ + { + "value": "BROOKLYN" + }, + { + "value": "BRONX" + }, + { + "value": "MANHATTAN" + }, + { + "value": "QUEENS" + }, + { + "value": "STATEN ISLAND" + } + ] + }, + { + "id": "law_cat_cd", + "label": "Law Category", + "logicalType": "SELECTED_FROM", + "possibleValues": [ + { + "value": "FELONY" + }, + { + "value": "MISDEMEANOR" + }, + { + "value": "VIOLATION" + } + ] + } + ] + } + ] + } + } + ] +} diff --git a/connector/user-config/override/nypd-connector/src/main/resources/global-config.json b/connector/user-config/override/nypd-connector/src/main/resources/global-config.json new file mode 100644 index 0000000..3f99e87 --- /dev/null +++ b/connector/user-config/override/nypd-connector/src/main/resources/global-config.json @@ -0,0 +1,6 @@ +{ + "schemaShortName": "NYPD-Complaints", + "schemaUrl": "/schema", + "chartingSchemesUrl": "/charting-schemes", + "userConfigUrl": "/userconfig" +} diff --git a/connector/user-config/override/nypd-connector/src/main/resources/other-config.json b/connector/user-config/override/nypd-connector/src/main/resources/other-config.json new file mode 100644 index 0000000..2349528 --- /dev/null +++ b/connector/user-config/override/nypd-connector/src/main/resources/other-config.json @@ -0,0 +1,65 @@ +{ + "defaultValues": { + "timeZoneId": "Europe/London", + "resultIdsPersistent": true + }, + "services": [ + { + "id": "nypd-search-service", + "name": "NYPD Connector: Search", + "description": "A service for conditional searches", + "clientConfigType": "FORM", + "clientConfigId": "searchForm", + "acquireUrl": "/search", + "validateUrl": "/search/validate" + } + ], + "clientConfigs": [ + { + "id": "searchForm", + "config": { + "sections": [ + { + "conditions": [ + { + "id": "boro_nm", + "label": "Borough Name", + "logicalType": "SELECTED_FROM", + "possibleValues": [ + { + "value": "BROOKLYN" + }, + { + "value": "BRONX" + }, + { + "value": "MANHATTAN" + }, + { + "value": "QUEENS" + }, + { + "value": "STATEN ISLAND" + } + ] + }, + { + "id": "law_cat_cd", + "label": "Law Category", + "logicalType": "SELECTED_FROM", + "possibleValues": [ + { + "value": "MISDEMEANOR" + }, + { + "value": "VIOLATION" + } + ] + } + ] + } + ] + } + } + ] +}