use of org.structr.common.EntityAndPropertiesContainer in project structr by structr.
the class IdDeserializationStrategy method deserialize.
@Override
public T deserialize(final SecurityContext securityContext, final Class<T> type, final S source, final Object context) throws FrameworkException {
final App app = StructrApp.getInstance(securityContext);
if (source != null) {
if (source instanceof Map) {
final Map<String, Object> properties = (Map<String, Object>) source;
Class<T> actualType = type;
if (actualType != null && actualType.isInterface()) {
// (creation wouldn't work otherwise anyway)
if (properties.containsKey(NodeInterface.type.jsonName())) {
final String typeFromInput = properties.get(NodeInterface.type.jsonName()).toString();
actualType = StructrApp.getConfiguration().getNodeEntityClass(typeFromInput);
// reset type on failed check
if (actualType == null) {
actualType = type;
}
}
}
final PropertyMap convertedProperties = PropertyMap.inputTypeToJavaType(securityContext, actualType, properties);
final Set<PropertyKey> allProperties = StructrApp.getConfiguration().getPropertySet(type, "all");
final Map<String, Object> foreignProps = new HashMap<>();
T relatedNode = null;
// If property map contains the uuid, search only for uuid
if (convertedProperties.containsKey(GraphObject.id)) {
relatedNode = (T) app.getNodeById(convertedProperties.get(GraphObject.id));
if (relatedNode != null) {
if (!SearchCommand.isTypeAssignableFromOtherType(type, relatedNode.getClass())) {
throw new FrameworkException(422, "Node type mismatch", new TypeToken(type.getSimpleName(), null, type.getSimpleName()));
}
for (final PropertyKey key : convertedProperties.keySet()) {
if (!key.isUnique() && !key.isCompound() && !isIdentifying(actualType, key) && !allProperties.contains(key)) {
// store "foreign" properties (those that are to be set on the newly created relationship
foreignProps.put(key.jsonName(), properties.get(key.jsonName()));
}
}
// node found, remove UUID
convertedProperties.remove(GraphObject.id);
}
} else {
final PropertyMap uniqueKeyValues = new PropertyMap();
for (final PropertyKey key : convertedProperties.keySet()) {
if (key.isUnique() || key.isCompound() || isIdentifying(actualType, key)) {
uniqueKeyValues.put(key, convertedProperties.get(key));
} else if (!allProperties.contains(key)) {
// store "foreign" properties (those that are to be set on the newly created relationship
foreignProps.put(key.jsonName(), properties.get(key.jsonName()));
}
}
// (this is quite similar to the Cypher MERGE command),
if (!uniqueKeyValues.isEmpty()) {
final List<T> possibleResults = app.nodeQuery(type).and(uniqueKeyValues).getAsList();
final int num = possibleResults.size();
switch(num) {
case 0:
// not found => will be created
break;
case 1:
relatedNode = possibleResults.get(0);
break;
default:
// more than one => not unique??
throw new FrameworkException(422, concat("Unable to resolve related node of type ", type.getSimpleName(), ", ambiguous result: found ", num, " nodes for the given property set."));
}
} else {
// throw exception here?
}
}
if (relatedNode == null) {
// no related node found, should we create one?
if (relationProperty != null) {
final Relation relation = relationProperty.getRelation();
if (relationProperty.doAutocreate()) {
return app.create(type, convertedProperties);
} else {
throw new FrameworkException(422, concat("Cannot create ", relation.getOtherType(type).getSimpleName(), ": no matching ", type.getSimpleName(), " found for the given property set ", convertedProperties, " and autoCreate has a value of ", relationProperty.getAutocreateFlagName()));
}
}
// FIXME: when can the relationProperty be null at all?
throw new FrameworkException(500, concat("Unable to resolve related node of type ", type.getSimpleName(), ", no relation defined."));
} else {
// set properties on related node?
if (!convertedProperties.isEmpty()) {
setProperties(securityContext, relatedNode, convertedProperties);
}
if (foreignProps.isEmpty()) {
return relatedNode;
} else {
return (T) new EntityAndPropertiesContainer(relatedNode, foreignProps);
}
}
} else if (type.isAssignableFrom(source.getClass())) {
return (T) source;
} else {
// interpret source as a raw ID string and fetch entity
final GraphObject obj = app.getNodeById(source.toString());
if (obj != null && !type.isAssignableFrom(obj.getClass())) {
throw new FrameworkException(422, "Node type mismatch", new TypeToken(obj.getClass().getSimpleName(), null, type.getSimpleName()));
}
return (T) obj;
}
}
return null;
}
Aggregations