Package com.buschmais.jqassistant.core.store.impl.dao

Source Code of com.buschmais.jqassistant.core.store.impl.dao.DescriptorDAOImpl$RowIterable

package com.buschmais.jqassistant.core.store.impl.dao;

import com.buschmais.jqassistant.core.model.api.descriptor.Descriptor;
import com.buschmais.jqassistant.core.store.api.DescriptorDAO;
import com.buschmais.jqassistant.core.store.api.QueryResult;
import com.buschmais.jqassistant.core.store.api.model.NodeProperty;
import com.buschmais.jqassistant.core.store.api.model.Relation;
import com.buschmais.jqassistant.core.store.impl.dao.mapper.DescriptorMapper;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;

public class DescriptorDAOImpl implements DescriptorDAO {

    private final class RowIterable implements Iterable<QueryResult.Row>, Closeable {

        private ResourceIterator<Map<String, Object>> iterator;

        private RowIterable(ResourceIterator<Map<String, Object>> iterator) {
            this.iterator = iterator;
        }

        @Override
        public Iterator<QueryResult.Row> iterator() {

            return new Iterator<QueryResult.Row>() {

                @Override
                public boolean hasNext() {
                    return iterator.hasNext();
                }

                @Override
                public QueryResult.Row next() {
                    Map<String, Object> row = new LinkedHashMap<>();
                    for (Entry<String, Object> entry : iterator.next().entrySet()) {
                        String name = entry.getKey();
                        Object value = entry.getValue();
                        Object decodedValue = decodeValue(value);
                        row.put(name, decodedValue);
                    }
                    return new QueryResult.Row(row);
                }

                @Override
                public void remove() {
                    iterator.remove();
                }

                private Object decodeValue(Object value) {
                    Object decodedValue;
                    if (value instanceof Node) {
                        Node node = (Node) value;
                        return getDescriptor(node);
                    } else {
                        decodedValue = value;
                    }
                    return decodedValue;
                }

            };
        }

        @Override
        public void close() throws IOException {
            iterator.close();
        }
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(DescriptorDAOImpl.class);

    private final GraphDatabaseService database;
    private final DescriptorMapperRegistry registry;
    private final ExecutionEngine executionEngine;

    private final DescriptorCache descriptorCache = new DescriptorCache();

    public DescriptorDAOImpl(DescriptorMapperRegistry registry, GraphDatabaseService database) {
        this.registry = registry;
        this.database = database;
        this.executionEngine = new ExecutionEngine(database);
    }

    @Override
    public <T extends Descriptor> void persist(T descriptor) {
        LOGGER.debug("Creating node for '{}'.", descriptor.getFullQualifiedName());
        DescriptorMapper<T> adapter = registry.getDescriptorMapper(descriptor.getClass());
        Node node = database.createNode(adapter.getCoreLabel());
        adapter.setId(descriptor, Long.valueOf(node.getId()));
        descriptorCache.put(descriptor);
    }

    @Override
    public void flush() {
        LOGGER.debug("Flushing changes to database.");
        for (Descriptor descriptor : descriptorCache.getDescriptors()) {
            LOGGER.debug("Flushing descriptor '{}'.", descriptor.getFullQualifiedName());
            Node node = getNode(descriptor);
            DescriptorMapper mapper = registry.getDescriptorMapper(descriptor.getClass());
            flushRelations(descriptor, node, mapper);
            flushProperties(descriptor, node, mapper);
            flushLabels(descriptor, node, mapper);
        }
        this.descriptorCache.flush();
    }

    @Override
    public <T extends Descriptor> T find(Class<T> type, String fullQualifiedName) {
        DescriptorMapper<Descriptor> mapper = registry.getDescriptorMapper(type);
        T descriptor = descriptorCache.findBy(fullQualifiedName);
        if (descriptor == null) {
            ResourceIterable<Node> nodesByLabelAndProperty = database.findNodesByLabelAndProperty(mapper.getCoreLabel(), NodeProperty.FQN.name(), fullQualifiedName);
            ResourceIterator<Node> iterator = nodesByLabelAndProperty.iterator();
            try {
                if (iterator.hasNext()) {
                    Node node = iterator.next();
                    descriptor = createDescriptor(node);
                }
            } finally {
                iterator.close();
            }
        }
        return descriptor;
    }

    @Override
    public QueryResult executeQuery(String query, Map<String, Object> parameters) {
        ExecutionResult result = executionEngine.execute(query, parameters);
        Iterable<QueryResult.Row> rowIterable = new RowIterable(result.iterator());
        return new QueryResult(result.columns(), rowIterable);
    }

    /**
     * Flushes the relations of the given descriptor to the {@link Node} it
     * represents.
     *
     * @param descriptor The descriptor.
     * @param node       The node.
     * @param mapper     The mapper.
     */
    private <T extends Descriptor> void flushRelations(T descriptor, Node node, DescriptorMapper<T> mapper) {
        Map<Relation, Set<? extends Descriptor>> relations = mapper.getRelations(descriptor);
        for (Entry<Relation, Set<? extends Descriptor>> relationEntry : relations.entrySet()) {
            Relation relationType = relationEntry.getKey();
            Set<? extends Descriptor> targetDescriptors = relationEntry.getValue();
            if (!targetDescriptors.isEmpty()) {
                Set<Node> existingTargetNodes = new HashSet<>();
                Iterable<Relationship> relationships = node.getRelationships(relationType, Direction.OUTGOING);
                if (relationships != null) {
                    for (Relationship relation : relationships) {
                        existingTargetNodes.add(relation.getEndNode());
                    }
                }
                for (Descriptor targetDescriptor : targetDescriptors) {
                    if (targetDescriptor != null) {
                        Node targetNode = getNode(targetDescriptor);
                        if (!existingTargetNodes.contains(targetNode)) {
                            node.createRelationshipTo(targetNode, relationType);
                        }
                    }
                }
            }
        }
    }

    /**
     * Flushes the properties of the given descriptor to the {@link Node} it
     * represents.
     *
     * @param descriptor The descriptor.
     * @param node       The node.
     * @param mapper     The mapper.
     */
    private <T extends Descriptor> void flushProperties(T descriptor, Node node, DescriptorMapper<T> mapper) {
        Map<NodeProperty, Object> properties = mapper.getProperties(descriptor);
        for (Entry<NodeProperty, Object> entry : properties.entrySet()) {
            NodeProperty property = entry.getKey();
            String name = property.name();
            Object value = entry.getValue();
            if (value == null) {
                if (node.hasProperty(name)) {
                    node.removeProperty(name);
                }
            } else {
                Object existingValue;
                if (node.hasProperty(property.name())) {
                    existingValue = node.getProperty(name);
                } else {
                    existingValue = null;
                }
                if (!value.equals(existingValue)) {
                    LOGGER.debug("Updating property '" + property + "' with value '" + value + "' on node '" + node.getId() + "'");
                    node.setProperty(name, value);
                }
            }
        }
    }

    /**
     * Flushes the labels of the given descriptor to the {@link Node} it
     * represents.
     *
     * @param descriptor The descriptor.
     * @param node       The node.
     * @param mapper     The mapper.
     */

    private <T extends Descriptor> void flushLabels(T descriptor, Node node, DescriptorMapper<T> mapper) {
        Set<Label> labels = mapper.getLabels(descriptor);
        for (Label label : labels) {
            node.addLabel(label);
        }
    }

    /**
     * Creates a descriptor instance from the given {@link Node}.
     * <p>
     * A new descriptor instance is created if no matching one can be found in
     * the {@link #descriptorCache}.
     * </p>
     *
     * @param node The {@link Node}.
     * @return The descriptor.
     */
    private <T extends Descriptor> T createDescriptor(Node node) {
        DescriptorMapper<T> mapper = registry.getDescriptorMapper(node);
        Class<T> type = getType(node);
        T descriptor = mapper.createInstance(type);
        mapper.setId(descriptor, Long.valueOf(node.getId()));
        descriptor.setFullQualifiedName((String) node.getProperty(NodeProperty.FQN.name()));
        this.descriptorCache.put(descriptor);
        // create outgoing relationships
        Map<Relation, Set<Descriptor>> relations = new HashMap<Relation, Set<Descriptor>>();
        for (Relationship relationship : node.getRelationships(Direction.OUTGOING)) {
            Relation relation = Relation.getRelation(relationship.getType().name());
            if (relation != null) {
                Node targetNode = relationship.getEndNode();
                Descriptor targetDescriptor = getDescriptor(targetNode);
                Set<Descriptor> set = relations.get(relation);
                if (set == null) {
                    set = new HashSet<>();
                    relations.put(relation, set);
                }
                set.add(targetDescriptor);
            }
        }
        mapper.setRelations(descriptor, relations);
        // Set properties
        for (String name : node.getPropertyKeys()) {
            NodeProperty nodeProperty = NodeProperty.getProperty(name);
            if (nodeProperty != null) {
                mapper.setProperty(descriptor, nodeProperty, node.getProperty(name));
            }
        }
        // Set labels
        for (Label label : node.getLabels()) {
            mapper.setLabel(descriptor, label);
        }
        return descriptor;
    }

    /**
     * Get the {@link Node} which represents the given descriptor.
     *
     * @param descriptor The descriptor.
     * @return The {@link Node}.
     */
    private <T extends Descriptor> Node getNode(T descriptor) {
        DescriptorMapper<T> mapper = registry.getDescriptorMapper(descriptor.getClass());
        Long id = mapper.getId(descriptor);
        return database.getNodeById(id);
    }

    /**
     * Get the {@link Descriptor} which represents the given node.
     *
     * @param node The node.
     * @return The {@link Descriptor}.
     */
    private Descriptor getDescriptor(Node node) {
        Class<Descriptor> type = getType(node);
        return find(type, (String) node.getProperty(NodeProperty.FQN.name()));
    }

    private <T extends Descriptor> Class<T> getType(Node node) {
        // find adapter and create instance
        DescriptorMapper<T> mapper = registry.getDescriptorMapper(node);
        // get labels from node.
        Set<Label> labels = new HashSet<>();
        for (Label label : node.getLabels()) {
            labels.add(label);
        }
        return (Class<T>) mapper.getType(labels);
    }
}
TOP

Related Classes of com.buschmais.jqassistant.core.store.impl.dao.DescriptorDAOImpl$RowIterable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.