Skip to content

Commit

Permalink
Eventparser functionality added (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
emichaf authored and ValentinTyhonov committed Apr 24, 2018
1 parent a90982a commit 290f883
Show file tree
Hide file tree
Showing 68 changed files with 1,176 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 0.5.8
- EventParser functionality added to endpoint /generateAndPublish (@param parseData added)

## 0.5.7
- Changed way of passing REMReM Generate Service uri and path from configs

Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ subprojects {
apply plugin: 'java'

//Latest version for publish
version = "0.5.7"
version = "0.5.8"

//Declare where to find the dependencies of project here
repositories {
Expand Down Expand Up @@ -123,6 +123,6 @@ subprojects {
testCompile 'junit:junit:4.12'
testCompile 'org.assertj:assertj-core:3.4.1'
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
testCompile 'com.jayway.jsonpath:json-path-assert:2.2.0'
testCompile 'com.jayway.jsonpath:json-path-assert:2.4.0'
}
}
1 change: 1 addition & 0 deletions publish-common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ dependencies {
//To publish messages to RabbitMQ
compile 'com.rabbitmq:amqp-client:3.5.7'
compile 'javax.servlet:javax.servlet-api:3.0.1'
compile 'com.jayway.jsonpath:json-path-assert:2.4.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
Copyright 2018 Ericsson AB.
For a full list of individual contributors, please see the commit history.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.ericsson.eiffel.remrem.publish.service;

import ch.qos.logback.classic.Logger;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import org.apache.commons.io.IOUtils;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EventTemplateHandler {
private static final Logger log = (Logger) LoggerFactory.getLogger(EventTemplateHandler.class);

// Paths in Semantics JAR
private static final String EVENT_TEMPLATE_PATH = "templates/";
private static final String EVENT_SCHEMA_PATH = "schemas/input/";

private static final String REGEXP_END_DIGITS = "\\[\\d+\\]$";

private final Configuration configuration = Configuration.builder()
.jsonProvider(new JacksonJsonNodeJsonProvider())
.mappingProvider(new JacksonMappingProvider())
.build();

// eventTemplateParser
public JsonNode eventTemplateParser(String jsonData , String eventName){
JsonNode updatedJson = null;
JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(factory);
JsonNode rootNode = null;
try {
String eventTemplate = accessFileInSemanticJar(EVENT_TEMPLATE_PATH + eventName.toLowerCase() + ".json");

rootNode = mapper.readTree(jsonData);
updatedJson = mapper.readValue(eventTemplate, JsonNode.class);
} catch (IOException e) {
log.error(e.getMessage(), e);
}

// For each key/value pair for parsing to template
Iterator<Map.Entry<String,JsonNode>> fieldsIterator = rootNode.fields();
while (fieldsIterator.hasNext()) {
Map.Entry<String, JsonNode> field = fieldsIterator.next();
// Parse values to template
// Check if POJO required for update in event template
Pattern p = Pattern.compile(REGEXP_END_DIGITS); // if ends with [d+]
Matcher m = p.matcher(field.getKey());

String myKey = "$." + templateParamHandler(field.getKey());

if(field.getValue().toString().equals("\"<%DELETE%>\"")){
updatedJson = jsonPathHandlerDelete(updatedJson, myKey);
}else if (m.find()) {
String myValue = field.getValue().toString();
try {
// Fetch Class name in Event Schema
String eventSchema = accessFileInSemanticJar(EVENT_SCHEMA_PATH + eventName + ".json");
// Filter javatype from Event Schema = class name
JsonNode jsonFromSchema = JsonPath.using(configuration).parse(eventSchema.toString()).read(schemaClassPathHandler(field.getKey().replaceAll(REGEXP_END_DIGITS, "")));
String myClassName = jsonFromSchema.toString().replace("[", "").replace("]", "").replace("\"", ""); // Ex ["com.ericsson.eiffel.semantics.events.PersistentLog"] to com.ericsson.eiffel.semantics.events.PersistentLog
// Initiate Class via reflection and map values - POJO
Class myClass = Class.forName(myClassName);
Object mapped2Pojo = mapper.readValue(myValue, myClass);
updatedJson = jsonPathHandlerSet(updatedJson, myKey, mapped2Pojo);
} catch (ClassNotFoundException e) {
// No POJO required for adding new item in Array (ie no key/value pairs)
updatedJson = jsonPathHandlerSet(updatedJson, myKey, myValue.toString().replace("\"", ""));
} catch (Exception e) {
log.error(e.getMessage(), e);
}

} else { // No POJO needed for update
Object myValue = field.getValue();
updatedJson = jsonPathHandlerSet(updatedJson, myKey, myValue);
}
} // while
return updatedJson;
}

private JsonNode jsonPathHandlerAdd(JsonNode updatedJson, String jsonKey, Object pojo){
updatedJson = JsonPath.using(configuration).parse(updatedJson.toString()).add(jsonKey, pojo).json();
return updatedJson;
}

private JsonNode jsonPathHandlerSet(JsonNode updatedJson, String jsonKey, Object JsonValue){
updatedJson = JsonPath.using(configuration).parse(updatedJson.toString()).set(jsonKey, JsonValue).json();
return updatedJson;
}

private JsonNode jsonPathHandlerDelete(JsonNode updatedJson, String jsonkey){
updatedJson = JsonPath.using(configuration).parse(updatedJson.toString()).delete(jsonkey).json();
return updatedJson;
}

private String templateParamHandler(String jsonKey){
String[] strArray = jsonKey.split("\\.");
Pattern p = Pattern.compile("links\\[\\d+\\]$"); // if ends with [d+]
Matcher m = p.matcher(strArray[0]);
try {
if (strArray != null && strArray.length >0 && strArray[0].equals("meta")) {
jsonKey = "msgParams." + jsonKey;
} else if (strArray != null && strArray.length >0 && strArray[0].equals("data") || m.find()) {
jsonKey = "eventParams." + jsonKey;
} else {
throw new IllegalArgumentException("jsonKey in data to be parsed is not valid : " + jsonKey);
}
}catch (ArrayIndexOutOfBoundsException e){
throw new IllegalArgumentException("jsonKey in data to be parsed is not valid : " + jsonKey);
}
return jsonKey;
}

private String schemaClassPathHandler(String jsonkey){
String[] strArray = jsonkey.split("\\.");
jsonkey = "";
for (String s: strArray) {
jsonkey = jsonkey + s+"[*].";
}
jsonkey = "$.properties." + jsonkey + "javaType";
return jsonkey;
}

private String accessFileInSemanticJar(String path) {
String result="";
InputStream input = EventTemplateHandler.class.getResourceAsStream(path);
if (input == null) {
input = EventTemplateHandler.class.getClassLoader().getResourceAsStream(path);
try {
result= IOUtils.toString(input, StandardCharsets.UTF_8);
} catch (IOException e) {
log.error(e.getMessage(), e);
} catch (NullPointerException e){
throw new NullPointerException("Can not find path: " + path);
}
}
return result;
}
} // class EventTemplateHandler
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void testRestTemplateCallSuccess() throws Exception {
when(restTemplate.postForEntity(Mockito.contains(correctURL), Mockito.<HttpEntity<String>>any(),
Mockito.eq(String.class), Mockito.anyMap())).thenReturn(responseOK);

ResponseEntity<?> elem = unit.generateAndPublish("eiffelsemantics", "eiffelactivityfinished", "", "", "",
ResponseEntity<?> elem = unit.generateAndPublish("eiffelsemantics", "eiffelactivityfinished", "", "", "",false,
body.getAsJsonObject());
assertEquals(elem.getStatusCode(), HttpStatus.OK);

Expand All @@ -131,7 +131,7 @@ public void testRestTemplateCallFail() throws Exception {
when(restTemplate.postForEntity(Mockito.contains(inCorrectURL), Mockito.<HttpEntity<String>>any(),
Mockito.eq(String.class), Mockito.anyMap())).thenReturn(responseBad);

ResponseEntity<?> elem = unit.generateAndPublish("eiffel3", "eiffelactivityfinished", "", "", "",
ResponseEntity<?> elem = unit.generateAndPublish("eiffel3", "eiffelactivityfinished", "", "", "",false,
body.getAsJsonObject());
assertEquals(elem.getStatusCode(), HttpStatus.BAD_REQUEST);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import java.util.Map;

import com.ericsson.eiffel.remrem.publish.constants.RemremPublishServiceConstants;
import com.ericsson.eiffel.remrem.publish.service.EventTemplateHandler;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.*;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -119,6 +121,8 @@ public ResponseEntity send(@ApiParam(value = "message protocol", required = true
* (not required)
* @param routingKey
* (not required)
* @param parseData
* (not required, default=false)
* @return A response entity which contains http status and result
*
* @use A typical CURL command: curl -H "Content-Type: application/json" -X POST
Expand All @@ -140,11 +144,23 @@ public ResponseEntity generateAndPublish(@ApiParam(value = "message protocol", r
@ApiParam(value = "user domain") @RequestParam(value = "ud", required = false) final String userDomain,
@ApiParam(value = "tag") @RequestParam(value = "tag", required = false) final String tag,
@ApiParam(value = "routing key") @RequestParam(value = "rk", required = false) final String routingKey,
@ApiParam(value = "parse data") @RequestParam(value = "parseData", required = false, defaultValue = "false") final Boolean parseData,
@ApiParam(value = "JSON message", required = true) @RequestBody final JsonObject bodyJson) {

String bodyJsonOut = null;
if(parseData) {
// -- parse params in incoming request -> body -------------
EventTemplateHandler eventTemplateHandler = new EventTemplateHandler();
JsonNode parsedTemplate = eventTemplateHandler.eventTemplateParser(bodyJson.toString(), msgType);
bodyJsonOut = parsedTemplate.toString();
log.info("Parsed template: " + bodyJsonOut);
}else{
bodyJsonOut = bodyJson.toString();
}

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(bodyJson.toString(), headers);
HttpEntity<String> entity = new HttpEntity<>(bodyJsonOut, headers);

try {
ResponseEntity<String> response = restTemplate.postForEntity(generateURLTemplate.getUrl(),
Expand Down
Loading

0 comments on commit 290f883

Please sign in to comment.