Search in sources :

Example 1 with EntityAndPropertiesContainer

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;
}
Also used : StructrApp(org.structr.core.app.StructrApp) App(org.structr.core.app.App) FrameworkException(org.structr.common.error.FrameworkException) HashMap(java.util.HashMap) GraphObject(org.structr.core.GraphObject) EntityAndPropertiesContainer(org.structr.common.EntityAndPropertiesContainer) Relation(org.structr.core.entity.Relation) PropertyMap(org.structr.core.property.PropertyMap) TypeToken(org.structr.common.error.TypeToken) GraphObject(org.structr.core.GraphObject) HashMap(java.util.HashMap) PropertyMap(org.structr.core.property.PropertyMap) Map(java.util.Map) PropertyKey(org.structr.core.property.PropertyKey)

Aggregations

HashMap (java.util.HashMap)1 Map (java.util.Map)1 EntityAndPropertiesContainer (org.structr.common.EntityAndPropertiesContainer)1 FrameworkException (org.structr.common.error.FrameworkException)1 TypeToken (org.structr.common.error.TypeToken)1 GraphObject (org.structr.core.GraphObject)1 App (org.structr.core.app.App)1 StructrApp (org.structr.core.app.StructrApp)1 Relation (org.structr.core.entity.Relation)1 PropertyKey (org.structr.core.property.PropertyKey)1 PropertyMap (org.structr.core.property.PropertyMap)1