Skip to content

Commit

Permalink
v1.4.0 public release
Browse files Browse the repository at this point in the history
  • Loading branch information
Afira-Zahari-i2 committed Dec 14, 2021
1 parent 20412a7 commit f9b7362
Show file tree
Hide file tree
Showing 5 changed files with 432 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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> T decode(String header, Class<T> 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<RequestCondition> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
]
}
]
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"schemaShortName": "NYPD-Complaints",
"schemaUrl": "/schema",
"chartingSchemesUrl": "/charting-schemes",
"userConfigUrl": "/userconfig"
}
Loading

0 comments on commit f9b7362

Please sign in to comment.