All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lordofthejars.nosqlunit.graph.parser.GraphMLReader Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package com.lordofthejars.nosqlunit.graph.parser;

import static com.lordofthejars.nosqlunit.graph.parser.TypeCaster.typeCastValue;

import java.io.IOError;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;

import org.apache.commons.lang.StringUtils;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.helpers.collection.MapUtil;

import com.google.common.base.Strings;

public class GraphMLReader {

	private GraphDatabaseService graphDatabaseService;

	public GraphMLReader(GraphDatabaseService graphDatabaseService) {
		this.graphDatabaseService = graphDatabaseService;
	}

	public void read(InputStream stream) {

		XMLInputFactory inputFactory = XMLInputFactory.newInstance();

		try {
			XMLStreamReader reader = inputFactory.createXMLStreamReader(stream);

			Map keyIdMap = new HashMap();
			Map keyTypesForNodes = new HashMap();
			Map keyTypesForEdges = new HashMap();
			Map keyAutoindexesForNodes = new HashMap();
			Map keyAutoindexesForEdges = new HashMap();

			Map nodes = new HashMap();
			List orphanEdges = new ArrayList();

			Node currentNode = null;
			Edge currentEdge = null;

			String currentVertexId = null;
			String currentEdgeId = null;

			boolean inVertex = false;
			boolean inEdge = false;
			int graphDepth = 0;

			while (reader.hasNext()) {

				Integer eventType = reader.next();
				if (eventType.equals(XMLEvent.START_ELEMENT)) {

					String elementName = reader.getName().getLocalPart();

					if (elementName.equals(GraphMLTokens.KEY)) {

						String id = reader.getAttributeValue(null, GraphMLTokens.ID);
						String attributeName = reader.getAttributeValue(null, GraphMLTokens.ATTR_NAME);
						String attributeType = reader.getAttributeValue(null, GraphMLTokens.ATTR_TYPE);
						String attributeAutoindexName = reader.getAttributeValue(null, GraphMLTokens.ATTR_AUTOINDEX);

						String attributeFor = reader.getAttributeValue(null, GraphMLTokens.FOR);

						keyIdMap.put(id, attributeName);

						if (GraphMLTokens.NODE.equalsIgnoreCase(attributeFor)) {

							keyTypesForNodes.put(attributeName, attributeType);

							if (attributeAutoindexName != null) {
								keyAutoindexesForNodes.put(attributeName, attributeAutoindexName);
							}

						} else {
							if (GraphMLTokens.EDGE.equalsIgnoreCase(attributeFor)) {

								keyTypesForEdges.put(attributeName, attributeType);

								if (attributeAutoindexName != null) {
									keyAutoindexesForEdges.put(attributeName, attributeAutoindexName);
								}
							}
						}

					} else if (elementName.equals(GraphMLTokens.NODE) && isRootGraph(graphDepth)) {

						currentVertexId = reader.getAttributeValue(null, GraphMLTokens.ID);

						if (currentVertexId != null) {
							Node node = graphDatabaseService.createNode();
							currentNode = node;
							nodes.put(currentVertexId, node);
						}

						inVertex = true;

					} else if (elementName.equals(GraphMLTokens.EDGE) && isRootGraph(graphDepth)) {

						currentEdgeId = reader.getAttributeValue(null, GraphMLTokens.ID);

						String edgeLabel = reader.getAttributeValue(null, GraphMLTokens.LABEL);
						edgeLabel = edgeLabel == null ? GraphMLTokens._DEFAULT : edgeLabel;

						String sourceId = reader.getAttributeValue(null, GraphMLTokens.SOURCE);
						String targetId = reader.getAttributeValue(null, GraphMLTokens.TARGET);

						currentEdge = new Edge(currentEdgeId, sourceId, targetId, edgeLabel);

						inEdge = true;

					} else if (elementName.equals(GraphMLTokens.DATA) && isRootGraph(graphDepth)) {

						String attributeName = reader.getAttributeValue(null, GraphMLTokens.KEY);

						if (isInsideNodeTag(inVertex)) {

							if (keyTypesForNodes.containsKey(attributeName)) {

								String value = reader.getElementText();
								Object typeCastValue = typeCastValue(attributeName, value, keyTypesForNodes);

								if (GraphMLTokens.ID.equals(attributeName)) {
									throw new IllegalArgumentException(
											"id key is reserved for node. Node with errorneous data: "
													+ currentVertexId);
								}

								if (currentNode != null) {
									// inserted directly to neo4j
									currentNode.setProperty(attributeName, typeCastValue);

									if (keyAutoindexesForNodes.containsKey(attributeName)) {
										String autoindexName = keyAutoindexesForNodes.get(attributeName);
										this.graphDatabaseService.index().forNodes(autoindexName)
												.add(currentNode, attributeName, typeCastValue);
									}

								}
							} else {
								throw new IllegalArgumentException("Attribute key: " + attributeName
										+ " is not declared.");
							}

						} else {

							if (isInsideEdgeTag(inEdge)) {

								if (keyTypesForEdges.containsKey(attributeName)) {

									String value = reader.getElementText();
									Object typeCastValue = typeCastValue(attributeName, value, keyTypesForEdges);

									if (GraphMLTokens.LABEL.equals(attributeName)) {
										throw new IllegalArgumentException(
												"label key is reserved for edge. Edge with errorneous data:  "
														+ currentEdgeId);
									}

									if (currentEdge != null) {
										// saved inmemory edge
										currentEdge.putData(attributeName, typeCastValue);
									}
								} else {
									throw new IllegalArgumentException("Attribute key: " + attributeName
											+ " is not declared.");
								}
							}
						}

					} else if (elementName.equals(GraphMLTokens.INDEX) && isRootGraph(graphDepth)) {
						
						if (isInsideNodeTag(inVertex)) {
							//add custom index over currentNode
							String indexName = reader.getAttributeValue(null, GraphMLTokens.ATTR_INDEX_NAME);
							String indexKey = reader.getAttributeValue(null, GraphMLTokens.ATTR_INDEX_KEY);
							String indexConfiguration = reader.getAttributeValue(null, GraphMLTokens.ATTR_INDEX_CONFIGURATION);
							String indexData = reader.getElementText();
							
							if(Strings.isNullOrEmpty(indexConfiguration)) {
								this.graphDatabaseService.index().forNodes(indexName).add(currentNode, indexKey, indexData);
							} else {
								String[] indexConfigurationTokens = indexConfiguration.split(GraphMLTokens.ATTR_INDEX_CONFIGURATION_SEPARATOR);
								this.graphDatabaseService.index().forNodes(indexName, MapUtil.stringMap(indexConfigurationTokens)).add(currentNode, indexKey, indexData);
							}
							
						} else {
							if (isInsideEdgeTag(inEdge)) {
								//add custom index over currentEdge
								String indexName = reader.getAttributeValue(null, GraphMLTokens.ATTR_INDEX_NAME);
								String indexKey = reader.getAttributeValue(null, GraphMLTokens.ATTR_INDEX_KEY);
								String indexConfiguration = reader.getAttributeValue(null, GraphMLTokens.ATTR_INDEX_CONFIGURATION);
								String indexData = reader.getElementText();
								
								if(Strings.isNullOrEmpty(indexConfiguration)) {
									currentEdge.putManualIndex(indexName, indexKey, indexData);
								} else {
									String[] indexConfigurationTokens = indexConfiguration.split(GraphMLTokens.ATTR_INDEX_CONFIGURATION_SEPARATOR);
									currentEdge.putManualIndex(indexName, indexKey, indexData, MapUtil.stringMap(indexConfigurationTokens));
								}
							}
						}
						
						
					} else if(elementName.equals(GraphMLTokens.GRAPH)) {
//						nodes.put("0", this.graphDatabaseService.getNodeById(0));
						graphDepth++;
					}

				} else {

					if (eventType.equals(XMLEvent.END_ELEMENT)) {

						String elementName = reader.getName().getLocalPart();

						if (elementName.equals(GraphMLTokens.NODE) && isRootGraph(graphDepth)) {

							currentNode = null;
							currentVertexId = null;
							inVertex = false;

						} else if (elementName.equals(GraphMLTokens.EDGE) && isRootGraph(graphDepth)) {

							addEdge(nodes, orphanEdges, currentEdge, keyAutoindexesForEdges);

							currentEdge = null;
							currentEdgeId = null;
							inEdge = false;

						} else if (elementName.equals(GraphMLTokens.GRAPHML)) {
							addOrphanEdgesWithNewParents(nodes, orphanEdges, keyAutoindexesForEdges);
						} else if (elementName.equals(GraphMLTokens.GRAPH)) {
							graphDepth--;
						}
					}
				}

			}

			reader.close();

		} catch (XMLStreamException e) {
			throw new IOError(e);
		}

	}

	private boolean isRootGraph(int graphDepth) {
		return graphDepth == 1;
	}

	private void addOrphanEdgesWithNewParents(Map nodes, List edgesWithoutNodeDefined,
			Map indexes) {
		for (Edge edge : edgesWithoutNodeDefined) {
			if (isEdgeInsertable(edge, nodes)) {
				Relationship relationship = edge.createLink(nodes);
				
				edge.createManualIndexes(graphDatabaseService, relationship);
				
				createRelationshipAutoIndexes(relationship, edge.getProps(), indexes);
			} else {
				throw new IllegalArgumentException("Next edge's nodes has not been declared. " + edge);
			}
		}
	}

	private void addEdge(Map nodes, List edgesWithoutNodeDefinedPreviously, Edge currentEdge,
			Map indexes) {
		if (currentEdge != null && isEdgeInsertable(currentEdge, nodes)) {

			Relationship relationship = currentEdge.createLink(nodes);
			currentEdge.createManualIndexes(graphDatabaseService, relationship);
			
			createRelationshipAutoIndexes(relationship, currentEdge.getProps(), indexes);

		} else {
			if (currentEdge != null) {
				edgesWithoutNodeDefinedPreviously.add(currentEdge);
			}
		}
	}

	private void createRelationshipAutoIndexes(Relationship relationship, Map props,
			Map indexes) {

		for (String prop : props.keySet()) {
			if (indexes.containsKey(prop)) {
				String indexName = indexes.get(prop);
				this.graphDatabaseService.index().forRelationships(indexName).add(relationship, prop, props.get(prop));
			}
		}

	}

	private boolean isEdgeInsertable(Edge edge, Map nodes) {
		return nodes.containsKey(edge.getSourceNodeId()) && nodes.containsKey(edge.getTargetNodeId());
	}

	private boolean isInsideEdgeTag(boolean inEdge) {
		return inEdge == true;
	}

	private boolean isInsideNodeTag(boolean inVertex) {
		return isInsideEdgeTag(inVertex);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy