Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,33 @@ public void tearDown() {

private void registerEventType(final String type) {
final Set<PropertyType> props = new HashSet<>();
registerEventType(type, props);
registerEventType(type, props, null, null);
}

private void registerEventType(final String type, final Set<PropertyType> props) {
final EventType eventType = new EventType(type, props, 1);
private void registerEventType(final String type, final Set<PropertyType> properties, final Set<PropertyType> source, final Set<PropertyType> target) {
final Set<PropertyType> typeProps = new HashSet<>();
if (properties != null) {
PropertyType propertiesPropType = new PropertyType();
propertiesPropType.setItemId("properties");
propertiesPropType.setValueTypeId("set");
propertiesPropType.setChildPropertyTypes(properties);
typeProps.add(propertiesPropType);
}
if (source != null) {
PropertyType sourcePropType = new PropertyType();
sourcePropType.setItemId("source");
sourcePropType.setValueTypeId("set");
sourcePropType.setChildPropertyTypes(source);
typeProps.add(sourcePropType);
}
if (target != null) {
PropertyType targetPropType = new PropertyType();
targetPropType.setItemId("target");
targetPropType.setValueTypeId("set");
targetPropType.setChildPropertyTypes(target);
typeProps.add(targetPropType);
}
final EventType eventType = new EventType(type, typeProps, 1);
eventService.registerEventType(eventType);
}

Expand Down Expand Up @@ -393,12 +415,12 @@ public void testCreateEventWithPropertiesValidation_Success() throws IOException
contextRequest.setProfileId(profileId);
contextRequest.setEvents(Arrays.asList(event));

final Set<PropertyType> typeProps = new HashSet<>();
final Set<PropertyType> propertiesPropTypes = new HashSet<>();
PropertyType floatProp = new PropertyType();
floatProp.setItemId("floatProperty");
floatProp.setValueTypeId("float");
typeProps.add(floatProp);
this.registerEventType(eventType, typeProps);
propertiesPropTypes.add(floatProp);
this.registerEventType(eventType, propertiesPropTypes, null, null);

//Act
HttpPost request = new HttpPost(URL + CONTEXT_URL);
Expand Down Expand Up @@ -431,12 +453,12 @@ public void testCreateEventWithPropertyValueValidation_Failure() throws IOExcept
contextRequest.setProfileId(profileId);
contextRequest.setEvents(Arrays.asList(event));

final Set<PropertyType> typeProps = new HashSet<>();
final Set<PropertyType> propertiesPropTypes = new HashSet<>();
PropertyType floatProp = new PropertyType();
floatProp.setItemId("floatProperty");
floatProp.setValueTypeId("float");
typeProps.add(floatProp);
this.registerEventType(eventType, typeProps);
propertiesPropTypes.add(floatProp);
this.registerEventType(eventType, propertiesPropTypes, null, null);

//Act
HttpPost request = new HttpPost(URL + CONTEXT_URL);
Expand All @@ -461,22 +483,23 @@ public void testCreateEventWithPropertyNameValidation_Failure() throws IOExcepti
event.setEventType(eventType);
event.setItemId(eventId);
Map<String, Object> props = new HashMap<>();
props.put("floatProperty", 3.14159);
props.put("ffloatProperty", 3.14159);
event.setProperties(props);

ContextRequest contextRequest = new ContextRequest();
contextRequest.setProfileId(profileId);
contextRequest.setEvents(Arrays.asList(event));

final Set<PropertyType> typeProps = new HashSet<>();
final Set<PropertyType> propertiesPropTypes = new HashSet<>();
PropertyType floatProp = new PropertyType();
floatProp.setItemId("floatProperty");
floatProp.setValueTypeId("float");
propertiesPropTypes.add(floatProp);
PropertyType geopointProp = new PropertyType();
geopointProp.setItemId("geopointProperty");
geopointProp.setValueTypeId("geopoint");
typeProps.add(geopointProp);
this.registerEventType(eventType, typeProps);
propertiesPropTypes.add(geopointProp);
this.registerEventType(eventType, propertiesPropTypes, null, null);

//Act
HttpPost request = new HttpPost(URL + CONTEXT_URL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,10 @@ protected Boolean execute(Object... args) throws IOException {
" }\n" +
" }\n" +
"}\n", XContentType.JSON);
if (mappings.get(itemName) == null) {
logger.warn("Couldn't find mapping for item {}, won't create monthly index template", itemName);
return false;
}
putIndexTemplateRequest.mapping(mappings.get(itemName), XContentType.JSON);
AcknowledgedResponse putIndexTemplateResponse = client.indices().putTemplate(putIndexTemplateRequest, RequestOptions.DEFAULT);
executedSuccessfully &= putIndexTemplateResponse.isAcknowledged();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@

package org.apache.unomi.services.impl.events;

import org.apache.unomi.api.Event;
import org.apache.unomi.api.EventType;
import org.apache.unomi.api.GeoPoint;
import org.apache.unomi.api.PluginType;
import org.apache.unomi.api.PropertyType;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.unomi.api.*;
import org.apache.unomi.api.services.EventTypeRegistry;
import org.apache.unomi.persistence.spi.CustomObjectMapper;
import org.osgi.framework.Bundle;
Expand All @@ -31,16 +28,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;

public class EventTypeRegistryImpl implements EventTypeRegistry, SynchronousBundleListener {

Expand Down Expand Up @@ -104,7 +95,13 @@ public boolean isValid(Event event) {
return false;
}

return areAllPropertiesValid(event.getProperties(), eventType.getPropertyTypes());
Set<PropertyType> propertiesPropertyTypes = findChildPropertyTypesById("properties", eventType.getPropertyTypes());
Set<PropertyType> sourcePropertyTypes = findChildPropertyTypesById("source", eventType.getPropertyTypes());
Set<PropertyType> targetPropertyTypes = findChildPropertyTypesById("target", eventType.getPropertyTypes());

return areObjectPropertiesValid(event.getProperties(), propertiesPropertyTypes) &&
areObjectPropertiesValid(event.getSource(), sourcePropertyTypes) &&
areObjectPropertiesValid(event.getTarget(), targetPropertyTypes);
}

/**
Expand All @@ -115,31 +112,81 @@ public boolean isValid(Event event) {
* @param types set of a predefined event type properties
* @return boolean result of validation
*/
private boolean areAllPropertiesValid(Map<String, Object> props, Set<PropertyType> types) {
private boolean areMapPropertiesValid(Map<Object, Object> props, Set<PropertyType> types) {
if (props == null || props.isEmpty() || types == null || types.isEmpty()) {
return true;
}
return props.entrySet().stream().allMatch(entry -> {
return types.stream().anyMatch(type -> {
if (!type.getItemId().equals(entry.getKey())) {
if (!type.getItemId().equals(entry.getKey().toString())) {
logger.warn("Event type validation error: map property {} is not allowed", entry.getKey().toString());
return false;
}
final Set<PropertyType> childTypes = type.getChildPropertyTypes();
if (childTypes.size() > 0 && entry.getValue() != null) {
try {
final Map<String, Object> childProps = (Map<String, Object>) entry.getValue();
return areAllPropertiesValid(childProps, childTypes);
return areObjectPropertiesValid(entry.getValue(), childTypes);
} catch (ClassCastException e) {
logger.error("Event property '{}' value is invalid: {}", entry.getKey(), e.getCause());
return false;
}
} else {
return testValueType(entry.getValue(), type.getValueTypeId());
boolean valueTypeValid = testValueType(entry.getValue(), type.getValueTypeId());
if (!valueTypeValid) {
logger.warn("Event type validation error: value type for property {} is not valid", entry.getKey().toString());
}
return valueTypeValid;
}
});
});
}

private boolean areObjectPropertiesValid(Object object, Set<PropertyType> types) {
if (object == null) {
return true;
}
if (object instanceof Map) {
return areMapPropertiesValid((Map<Object,Object>) object, types);
}
PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(object);
return Arrays.stream(propertyDescriptors).allMatch(propertyDescriptor -> {
PropertyType propertyType = findPropertyTypeById(propertyDescriptor.getName(), types);
if (propertyType == null) {
logger.warn("Event type validation error: couldn't find property type for property {}", propertyDescriptor.getName());
return false;
}
if ("set".equals(propertyType.getValueTypeId())) {
boolean setPropertiesValid = false;
try {
setPropertiesValid = areObjectPropertiesValid(PropertyUtils.getProperty(object, propertyDescriptor.getName()), propertyType.getChildPropertyTypes());
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
logger.error("Error accessing property {} on object {}: {}", propertyDescriptor.getName(), object.toString(), e);
return false;
}
if (!setPropertiesValid) {
logger.warn("Event type validation error: set property for property {} are not valid", propertyDescriptor.getName());
return false;
}
}
return true;
});
}

private Set<PropertyType> findChildPropertyTypesById(String id, Set<PropertyType> types) {
PropertyType propertyType = findPropertyTypeById(id, types);
if (propertyType == null) {
return new HashSet<>();
} else {
return propertyType.getChildPropertyTypes();
}
}

private PropertyType findPropertyTypeById(String id, Set<PropertyType> types) {
Optional<PropertyType> optionalPropertyType = types.stream().filter(propertyType -> propertyType.getItemId().equals(id)).findFirst();
return optionalPropertyType.orElse(null);

}

private boolean testValueType(final Object value, final String valueTypeId) {
switch (valueTypeId) {
case "integer":
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"type" : "anonymizeProfile",
"propertyTypes" : [
{
"itemId": "target",
"type": "set",
"childPropertyTypes": [
{
"itemId": "itemId",
"type": "string"
},
{
"itemId": "properties",
"type": "set"
},
{
"itemId": "systemProperties",
"type": "set"
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"type" : "articleCompleted",
"propertyTypes" : [
{
"itemId": "properties",
"type": "set"
},
{
"itemId" : "source",
"type": "set",
"childPropertyTypes" : [
{
"itemId" : "itemId",
"type" : "string"
},
{
"itemId" : "itemType",
"type" : "string"
},
{
"itemId" : "scope",
"type" : "string"
},
{
"itemId" : "properties",
"type" : "set"
},
{
"itemId": "version",
"type": "long"
},
{
"itemId": "systemMetadata",
"type": "set"
}
]
},
{
"itemId" : "target",
"type": "set",
"childPropertyTypes" : [
{
"itemId" : "itemId",
"type" : "string"
},
{
"itemId" : "itemType",
"type" : "string"
},
{
"itemId" : "scope",
"type" : "string"
},
{
"itemId" : "properties",
"type" : "set"
},
{
"itemId": "version",
"type": "long"
},
{
"itemId": "systemMetadata",
"type": "set"
}
]
}
]
}
Loading