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

org.eroq.plugin.neo4jclient.Neo4jClientFactory Maven / Gradle / Ivy

package org.eroq.plugin.neo4jclient;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.test.TestGraphDatabaseFactory;

public class Neo4jClientFactory {
	
	public abstract static class LocalNeo4jClient extends Neo4jClient {
		protected GraphDatabaseService graphDb;
		public Neo4jResult query(String query, Map parameters) {
			try ( Transaction tx = graphDb.beginTx() )
			{
				Result result = graphDb.execute(query, (parameters != null) ? parameters : new HashMap<>());
				List columns = result.columns();
				List neo4jData = new ArrayList<>();
				while(result.hasNext()) {
					Map dataLine = result.next();
					Map row = new HashMap<>();
					List graphNodes = new ArrayList<>();
					List graphRelationship = new ArrayList<>();
					for(String column: columns) {
						row.put(column, convert(dataLine.get(column), graphNodes, graphRelationship));
					}
					Neo4jEntry neo4jEntry = new Neo4jEntry(row, graphNodes, graphRelationship);
					neo4jData.add(neo4jEntry);
				}
				Neo4jResult neo4jResult = new Neo4jResult(columns, neo4jData);
			    tx.success();
			    return neo4jResult;
			}
		}
		private Object convert(Object object, List graphNodes, List graphRelationships) {
			if(object==null) {
				return null;
			}
			// Check if object is Node or Relationship
			if(object instanceof Node) {
				Node node = (Node)object;
				Set convertedLabels = new HashSet<>();
				for(Label label: node.getLabels()) {
					convertedLabels.add(label.name());
				}
				@SuppressWarnings("unchecked")
				Map convertedProperties = (Map)convert(node.getAllProperties(), graphNodes, graphRelationships);
				Neo4jNode neo4jNode = new Neo4jNode(node.getId(), convertedLabels, convertedProperties);
				graphNodes.add(neo4jNode);
				object = node.getAllProperties();
			} else if (object instanceof Relationship) {
				Relationship relationship = (Relationship)object;
				String convertedType = relationship.getType().name();
				@SuppressWarnings("unchecked")
				Map convertedProperties = (Map)convert(relationship.getAllProperties(), graphNodes, graphRelationships);
				Neo4jRelationship neo4jRelationship = new Neo4jRelationship(relationship.getId(), convertedType, relationship.getStartNode().getId(), relationship.getEndNode().getId(), convertedProperties);
				graphRelationships.add(neo4jRelationship);
				object = relationship.getAllProperties();
			}
			// Convert basic objects
			if(object instanceof Map) {
				@SuppressWarnings("unchecked")
				Map map = (Map)object;
				Map convertedMap = new HashMap<>();
				for(String key: map.keySet()) {
					convertedMap.put(key, convert(map.get(key), graphNodes, graphRelationships));
				}
				return convertedMap;
			} else if(object instanceof List) {
				@SuppressWarnings("unchecked")
				List list = (List)object;
				List convertedList = new ArrayList<>();
				for(Object value: list) {
					convertedList.add(convert(value, graphNodes, graphRelationships));
				}
				return convertedList;
			} else if(
				object instanceof Boolean || object instanceof Boolean[] || object instanceof boolean[] ||
				object instanceof Byte || object instanceof Byte[] || object instanceof byte[] ||
				object instanceof Short || object instanceof Short[] || object instanceof short[] ||
				object instanceof Integer || object instanceof Integer[] || object instanceof int[] ||
				object instanceof Long || object instanceof Long[] || object instanceof long[] ||
				object instanceof Float || object instanceof Float[] || object instanceof float[] ||
				object instanceof Double || object instanceof Double[] || object instanceof double[] ||
				object instanceof Character || object instanceof Character[] || object instanceof char[] ||
				object instanceof String ||  object instanceof String[]) {
				
				if(object instanceof Integer) {
					return (Long)(long)(Integer)object;
				} else if(object instanceof Integer[]) {
					Integer[] original  = (Integer[])object;
					Long[] result = new Long[original.length];
					int p = 0;
					for(Integer n: original) {
						result[p++] = (Long)(long)(Integer)n;
					}
					return result;
				} else if(object instanceof int[]) {
					int[] original  = (int[])object;
					Long[] result = new Long[original.length];
					int p = 0;
					for(Integer n: original) {
						result[p++] = (Long)(long)(Integer)n;
					}
					return result;
				}

				return object;
			} else {
				throw new IllegalArgumentException("Cannot convert objects of type: "+object.getClass().getName());
			}
			
		}
	}

	public static class EmbeddedNeo4jClient extends LocalNeo4jClient {
		private EmbeddedNeo4jClient(String path) {
			graphDb = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(new File(path))
				    .setConfig( GraphDatabaseSettings.allow_store_upgrade, "true")
				    .newGraphDatabase();
			Runtime.getRuntime().addShutdownHook( new Thread() {
		        @Override
		        public void run()
		        {
		            graphDb.shutdown();
		        }
		    });
		}
	}
	
	public static class MemoryNeo4jClient extends LocalNeo4jClient {
		private MemoryNeo4jClient() {
			GraphDatabaseService graphDb = new TestGraphDatabaseFactory().newImpermanentDatabase();
			Runtime.getRuntime().addShutdownHook( new Thread() {
		        @Override
		        public void run()
		        {
		            graphDb.shutdown();
		        }
		    });
		}
	}
		
	public static class RemoteNeo4jClient extends Neo4jClient {
		
		@SuppressWarnings("unused")
		private static class Statement {
			public String statement;
			public List resultDataContents;
			public Map parameters;
			public Boolean includeStats;
		}
		
		private static class QueryRequest {
			public List statements;
		}
		
		private static class QueryResponse {
			public List results;
			public List errors;
		}
		
		private static class Result {
			public List columns;
			public List data;
		}
		
		private static class Entry {
			public List row;
			public Graph graph;
		}
		
		private static class Graph {
			public List nodes;
			public List relationships;
		}
		
		private static class ClientNode {
			public String id;
			public Set labels;
			public Map properties;
		}
		
		private static class ClientRelationship {
			public String id;
			public String type;
			public Map properties;
			public String startNode;
			public String endNode;
		}
		
		private static class Error {
			@SuppressWarnings("unused")
			public String code;
			public String message;
			@SuppressWarnings("unused")
			public String stackTrace;
		}
		
		private static class RemoteNeo4jClientException extends RuntimeException {

			public RemoteNeo4jClientException(String message) {
				super(message);
			}
		}
		
		private WebTarget webTarget;
		
		private RemoteNeo4jClient(String url, String username, String password) {
			Client httpClient = ClientBuilder.newClient();
			
			if((username!=null && !username.isEmpty()) || (password!=null && !password.isEmpty())) {
				httpClient.register(HttpAuthenticationFeature.basic(username, password));				
			}
			webTarget = httpClient.target(url).path("db").path("data");
		}
		
		public Neo4jResult query(String query, Map params) {
			WebTarget transactionalEndpointTarget = webTarget.path("transaction").path("commit");

			QueryRequest queryRequest = new QueryRequest();
			
			queryRequest.statements = new ArrayList<>();
			Statement statement = new Statement();
			statement.statement = query;
			statement.resultDataContents = Arrays.asList(new String[] {"row", "graph"});
			statement.includeStats = false;
			statement.parameters = params;
			queryRequest.statements.add(statement);
			
			Entity queryRequestEntity = Entity.entity(queryRequest, MediaType.APPLICATION_JSON_TYPE);
			
			Response response = transactionalEndpointTarget
				.request()
				.accept(MediaType.APPLICATION_JSON)
				.post(queryRequestEntity);
			
			List entries = new ArrayList<>();
			QueryResponse queryResponse = response.readEntity(QueryResponse.class);
			if(queryResponse.errors != null && queryResponse.errors.size()>0) {
				throw new RemoteNeo4jClientException(queryResponse.errors.get(0).message);
			}
			if(queryResponse.results == null || queryResponse.results.size()==0) {
				throw new RemoteNeo4jClientException("No result");
			}
			List columns = queryResponse.results.get(0).columns;
			for(Entry entry: queryResponse.results.get(0).data) {
				Map map = new HashMap<>();
				for(int i=0; i nodes = new ArrayList<>();
				for(ClientNode clientNode: entry.graph.nodes) {
					@SuppressWarnings("unchecked")
					Map convertedProperties = (Map)convert(clientNode.properties);
					nodes.add(new Neo4jNode(Long.parseLong(clientNode.id), clientNode.labels, convertedProperties));
				}
				List relationships = new ArrayList<>();
				for(ClientRelationship clientRelationship: entry.graph.relationships) {
					@SuppressWarnings("unchecked")
					Map convertedProperties = (Map)convert(clientRelationship.properties);
					relationships.add(new Neo4jRelationship(Long.parseLong(clientRelationship.id), clientRelationship.type, Long.parseLong(clientRelationship.startNode), Long.parseLong(clientRelationship.endNode), convertedProperties));
				}
				Neo4jEntry e = new Neo4jEntry(map, nodes, relationships);
				entries.add(e);
			}
			return new Neo4jResult(queryResponse.results.get(0).columns, entries);
		}

		private Object convert(Object object) {
			if(object==null) {
				return null;
			}
			// Convert basic objects
			if(object instanceof Map) {
				@SuppressWarnings("unchecked")
				Map map = (Map)object;
				Map convertedMap = new HashMap<>();
				for(String key: map.keySet()) {
					convertedMap.put(key, convert(map.get(key)));
				}
				return convertedMap;
			} else if(object instanceof List) {
				@SuppressWarnings("unchecked")
				List list = (List)object;
				List convertedList = new ArrayList<>();
				for(Object value: list) {
					convertedList.add(convert(value));
				}
				return convertedList;
			} else if(
				object instanceof Boolean || object instanceof Boolean[] || object instanceof boolean[] ||
				object instanceof Byte || object instanceof Byte[] || object instanceof byte[] ||
				object instanceof Short || object instanceof Short[] || object instanceof short[] ||
				object instanceof Integer || object instanceof Integer[] || object instanceof int[] ||
				object instanceof Long || object instanceof Long[] || object instanceof long[] ||
				object instanceof Float || object instanceof Float[] || object instanceof float[] ||
				object instanceof Double || object instanceof Double[] || object instanceof double[] ||
				object instanceof Character || object instanceof Character[] || object instanceof char[] ||
				object instanceof String ||  object instanceof String[]) {
				
				if(object instanceof Integer) {
					return (Long)(long)(Integer)object;
				} else if(object instanceof Integer[]) {
					Integer[] original  = (Integer[])object;
					Long[] result = new Long[original.length];
					int p = 0;
					for(Integer n: original) {
						result[p++] = (Long)(long)(Integer)n;
					}
					return result;
				} else if(object instanceof int[]) {
					int[] original  = (int[])object;
					Long[] result = new Long[original.length];
					int p = 0;
					for(Integer n: original) {
						result[p++] = (Long)(long)(Integer)n;
					}
					return result;
				}
				
				return object;
			} else {
				throw new IllegalArgumentException("Cannot convert objects of type: "+object.getClass().getName());
			}
			
		}

	}
	
	public static EmbeddedNeo4jClient createEmbeddedClient(String path) {
		return new EmbeddedNeo4jClient(path);
	}

	public static RemoteNeo4jClient createRemoteClient(String url, String username, String password) {
		return new RemoteNeo4jClient(url, username, password);
	}

	public static MemoryNeo4jClient createMemoryClient() {
		return new MemoryNeo4jClient();
	}
	
}