
fiftyone.pipeline.jsonbuilder.flowelements.JsonBuilderElement Maven / Gradle / Ivy
/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close,
* Caversham, Reading, Berkshire, United Kingdom RG4 7BY.
*
* This Original Work is licensed under the European Union Public Licence (EUPL)
* v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */
package fiftyone.pipeline.jsonbuilder.flowelements;
import fiftyone.pipeline.core.data.ElementData;
import fiftyone.pipeline.core.data.ElementPropertyMetaData;
import fiftyone.pipeline.core.data.ElementPropertyMetaDataDefault;
import fiftyone.pipeline.core.data.EvidenceKeyFilter;
import fiftyone.pipeline.core.data.EvidenceKeyFilterWhitelist;
import fiftyone.pipeline.core.data.FlowData;
import fiftyone.pipeline.core.data.FlowError;
import fiftyone.pipeline.core.data.PropertyMatcher;
import fiftyone.pipeline.core.data.TryGetResult;
import fiftyone.pipeline.core.data.factories.ElementDataFactory;
import fiftyone.pipeline.core.data.types.JavaScript;
import fiftyone.pipeline.core.exceptions.PipelineConfigurationException;
import fiftyone.pipeline.core.flowelements.FlowElementBase;
import fiftyone.pipeline.engines.data.AspectPropertyValue;
import fiftyone.pipeline.engines.exceptions.NoValueException;
import fiftyone.pipeline.jsonbuilder.Constants;
import fiftyone.pipeline.jsonbuilder.data.JsonBuilderData;
import java.util.*;
import org.json.JSONObject;
import org.slf4j.Logger;
import static fiftyone.pipeline.core.Constants.EVIDENCE_SEPERATOR;
//! [class]
//! [constructor]
/**
* The JsonBuilderElement takes accessible properties and adds the property
* key:values to the Json object. The element will also add any errors which
* have been recorded in the FlowData.
*/
public class JsonBuilderElement
extends FlowElementBase
implements JsonBuilder {
/**
* Default constructor.
* @param logger The logger.
* @param elementDataFactory The element data factory.
*/
public JsonBuilderElement(
Logger logger,
ElementDataFactory elementDataFactory) {
super(logger, elementDataFactory);
}
//! [constructor]
@Override
protected void processInternal(FlowData data) throws Exception {
JsonBuilderDataInternal elementData =
(JsonBuilderDataInternal)data.getOrAdd(
getElementDataKey(),
getDataFactory());
String jsonString = buildJson(data);
elementData.setJson(jsonString);
}
@Override
public String getElementDataKey() {
return "json-builder";
}
@Override
public EvidenceKeyFilter getEvidenceKeyFilter() {
return new EvidenceKeyFilterWhitelist(new ArrayList(){},
String.CASE_INSENSITIVE_ORDER);
}
@Override
public List getProperties() {
return Collections.singletonList(
(ElementPropertyMetaData) new ElementPropertyMetaDataDefault(
"json",
this,
"json",
String.class,
true));
}
@Override
protected void managedResourcesCleanup() {
// Nothing to clean up here.
}
@Override
protected void unmanagedResourcesCleanup() {
// Nothing to clean up here.
}
/**
* Create and populate a JSON string from the specified data.
* @param data to convert to JSON
* @return a string containing the data in JSON format
* @throws Exception
*/
private String buildJson(FlowData data) throws Exception {
Integer sequenceNumber;
try {
sequenceNumber = getSequenceNumber(data);
} catch (Exception e) {
throw new PipelineConfigurationException("Make sure there is a "
+ "SequenceElement placed before this JsonBuilderElement "
+ "in the pipeline", e);
}
Map allProperties = getAllProperties(data);
// Only populate the javascript properties if the sequence
// has not reached max iterations.
if (sequenceNumber < Constants.MAX_JAVASCRIPT_ITERATIONS) {
addJavaScriptProperties(data, allProperties);
}
addErrors(data, allProperties);
return buildJson(allProperties);
}
private int getSequenceNumber(FlowData data) throws Exception {
TryGetResult sequence = data.tryGetEvidence(
"query.sequence",
Integer.class);
if(sequence.hasValue() == false) {
throw new Exception("Sequence number not present in evidence. " +
"this is mandatory.");
}
return sequence.getValue();
}
private Map getAllProperties(FlowData data) throws NoValueException {
Map allProperties = new HashMap<>();
for (Map.Entry element : data.elementDataAsMap().entrySet()) {
if (allProperties.containsKey(element.getKey().toLowerCase()) == false)
{
Map elementProperties = new HashMap<>();
ElementData datum = (ElementData)(element.getValue());
for (Map.Entry elementProperty : datum.asKeyMap().entrySet()) {
Object value = elementProperty.getValue();
Object nullReason = "Unknown";
if(elementProperty.getValue() instanceof AspectPropertyValue) {
AspectPropertyValue apv =
(AspectPropertyValue)elementProperty.getValue();
if(apv.hasValue()) {
value = apv.getValue();
}
else {
value = null;
nullReason = apv.getNoValueMessage();
}
}
elementProperties.put(elementProperty.getKey().toLowerCase(), value);
if(value == null) {
elementProperties.put(
elementProperty.getKey().toLowerCase() + "nullreason",
nullReason);
}
}
allProperties.put(element.getKey().toLowerCase(), elementProperties);
}
}
return allProperties;
}
private void addJavaScriptProperties(
FlowData data,
Map allProperties) {
List javascriptProperties =
getJavaScriptProperties(data, allProperties);
if (javascriptProperties.size() > 0) {
allProperties.put("javascriptProperties", javascriptProperties);
}
}
private List getJavaScriptProperties(
FlowData data,
Map allProperties) {
// Create a list of the available properties in the form of
// "elementdatakey.property" from a
// Dictionary> of properties
// structured as >
List props = new ArrayList<>();
for (Map.Entry element : allProperties.entrySet()) {
Object entryObject = element.getValue();
if (entryObject instanceof Map) {
Map entry = (Map)entryObject;
for (Object propertyObject : entry.entrySet()) {
Map.Entry property = (Map.Entry)propertyObject;
props.add(
element.getKey().toLowerCase() + EVIDENCE_SEPERATOR + property.getKey().toString().toLowerCase());
}
}
}
return getJavaScriptProperties(data, props);
}
private boolean containsIgnoreCase(List list, String key) {
for (String item : list) {
if (item.equalsIgnoreCase(key)) {
return true;
}
}
return false;
}
private List getJavaScriptProperties(
FlowData data,
List props) {
// Get a list of all the JavaScript properties which are available.
Map javascriptPropertiesMap =
data.getWhere(new JsPropertyMatcher());
// Copy the keys to an array, otherwise we are removing from the same
// Map we are iterating over, which causes a concurrent modification
// exception.
String[] keys = new String[0];
keys = javascriptPropertiesMap.keySet().toArray(keys);
for(String key : keys) {
if(containsIgnoreCase(props, key) == false) {
javascriptPropertiesMap.remove(key.toLowerCase());
}
}
List javascriptPropertyNames = new ArrayList<>();
for (String name : javascriptPropertiesMap.keySet()) {
javascriptPropertyNames.add(name.toLowerCase());
}
return javascriptPropertyNames;
}
private void addErrors(FlowData data, Map allProperties) {
// If there are any errors then add them to the Json.
if (data.getErrors() != null && data.getErrors().size() > 0) {
Map> errors = new HashMap<>();
for (FlowError error : data.getErrors())
{
if (errors.containsKey(error.getFlowElement().getElementDataKey())) {
errors.get(error.getFlowElement().getElementDataKey()).add(error.getThrowable().getMessage());
} else {
errors.put(error.getFlowElement().getElementDataKey(),
Collections.singletonList(
error.getThrowable().getMessage()));
}
}
allProperties.put("errors", errors);
}
}
private String buildJson(Map allProperties) {
JSONObject json = new JSONObject();
for (Map.Entry entry : allProperties.entrySet()) {
if (entry.getValue() instanceof Map) {
Map map = new HashMap<>();
@SuppressWarnings("unchecked")
Map properties = (Map)entry.getValue();
for (Map.Entry ent : properties.entrySet()) {
Object value = ent.getValue();
if(value instanceof JavaScript)
value = value.toString();
map.put(ent.getKey(), value);
}
json.put(entry.getKey(), map);
} else {
json.put(entry.getKey(), entry.getValue());
}
}
return json.toString(2);
}
}
class JsPropertyMatcher implements PropertyMatcher {
@Override
public boolean isMatch(ElementPropertyMetaData property) {
return property.getType() == JavaScript.class;
}
}
//! [class]
© 2015 - 2025 Weber Informatics LLC | Privacy Policy