提交 4aa435bc 编写于 作者: L Lasse Westh-Nielsen

Merge branch '1.5-maint' of file:////Users/lassewesth/processed-repos/gremlin-plugin into 1.5-maint

*.log
*~
\#*
target
*.swp
.project
.classpath
.settings
.scala_dependencies
.factorypath
*.iws
*.ipr
*.iml
.idea
.DS_Store
artifacts
此差异已折叠。
Neo4j
Copyright © 2002-2012 Network Engine for Objects in Lund AB (referred to
in this notice as “Neo Technology”)
[http://neotechnology.com]
This product includes software ("Software") developed by Neo Technology.
The copyright in the bundled Neo4j graph database (including the
Software) is owned by Neo Technology. The Software developed and owned
by Neo Technology is licensed under the GNU GENERAL PUBLIC LICENSE
Version 3 (http://www.fsf.org/licensing/licenses/gpl-3.0.html) ("GPL")
to all third parties and that license, as required by the GPL, is
included in the LICENSE.txt file.
However, if you have executed an End User Software License and Services
Agreement or an OEM Software License and Support Services Agreement, or
another commercial license agreement with Neo Technology or one of its
affiliates (each, a "Commercial Agreement"), the terms of the license in
such Commercial Agreement will supersede the GPL and you may use the
software solely pursuant to the terms of the relevant Commercial
Agreement.
Third party libraries
---------------------
Third party libraries are only used to build the plugin,
but the plugin itself doesn't re-distribute any libraries.
This is a beginning of providing [Gremlin](http://gremlin.tinkerpop.com) backend scripting to the [Neo4j Server](http://neo4j.org). to deploy, please do the following
mvn clean package
cp target/gremlin-translator-plugin-0.1-SNAPSHOT.jar $NEO4J_HOME/plugins
cd $NEO4J_HOME
bin/neo4j restart
Integration testing:
mvn clean package
source set_env.sh
rake
access the plugin
curl localhost:7474/db/data/
{
"relationship_index" : "http://localhost:7474/db/data/index/relationship",
"node" : "http://localhost:7474/db/data/node",
"relationship_types" : "http://localhost:7474/db/data/relationship/types",
"extensions_info" : "http://localhost:7474/db/data/ext",
"node_index" : "http://localhost:7474/db/data/index/node",
"reference_node" : "http://localhost:7474/db/data/node/0",
"extensions" : {
"GremlinPlugin" : {
"execute_script" : "http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script"
}
}
submit (HTTP POST) a Gremlin script `i=g.V(2);i.outE.inV` returning a list of nodes, URL encoded:
curl -d "script=i+%3D+g.v%282%29%3Bi.outE.inV" http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
[ {
"outgoing_relationships" : "http://localhost:7474/db/data/node/0/relationships/out",
"data" : {
},
"traverse" : "http://localhost:7474/db/data/node/0/traverse/{returnType}",
"all_typed_relationships" : "http://localhost:7474/db/data/node/0/relationships/all/{-list|&|types}",
"property" : "http://localhost:7474/db/data/node/0/properties/{key}",
"self" : "http://localhost:7474/db/data/node/0",
"properties" : "http://localhost:7474/db/data/node/0/properties",
"outgoing_typed_relationships" : "http://localhost:7474/db/data/node/0/relationships/out/{-list|&|types}",
"incoming_relationships" : "http://localhost:7474/db/data/node/0/relationships/in",
"extensions" : {
},
"create_relationship" : "http://localhost:7474/db/data/node/0/relationships",
"all_relationships" : "http://localhost:7474/db/data/node/0/relationships/all",
"incoming_typed_relationships" : "http://localhost:7474/db/data/node/0/relationships/in/{-list|&|types}"
} ]
\ No newline at end of file
# $:.unshift(File.dirname(__FILE__) + '/../../lib')
require 'cucumber/rake/task'
Cucumber::Rake::Task.new
task :default => 'cucumber'
\ No newline at end of file
Feature: Download and unpack Neo4j Server
In order to get Neo4j Server
A user
Should be able to download and unpack a platform appropriate archive from the web
Background:
Given a platform supported by Neo4j
And a working directory at relative path "target"
And set Neo4j Home to "neo4j_home"
And Neo4j version based on system property "NEO4J_VERSION"
And Neo4j product based on system property "NEO4J_PRODUCT"
And a web site at host "dist.neo4j.org" or system property "DOWNLOAD_LOCATION"
And plugin based on system property "DOWNLOAD_PLUGIN_LOCATION"
Scenario: Download Neo4j
When I download Neo4j (if I haven't already)
Then the working directory should contain a Neo4j archive
And I download the plugin (if I haven't already)
Then the "plugin.zip" should exists
Scenario: Unpack downloaded archive
When I unpack the archive into Neo4j Home
Then Neo4j Home should contain a Neo4j Server installation
And the Neo4j version of the installation should be correct
And in Windows I will patch the "neo4j_home/conf/neo4j-wrapper.conf" adding "wrapper.java.command" to "#{ENV['JAVA_HOME']}\\bin\\java.exe"
Then I unzip the "plugin.zip" into "neo4j_home/plugins"
Feature: Start and stop Neo4j Server
The Neo4j server should start and stop using a command line script
Background:
Given a platform supported by Neo4j
And a working directory at relative path "target"
And set Neo4j Home to "neo4j_home"
And Neo4j Home should contain a Neo4j Server installation
Scenario: Start Neo4j Server
When I start Neo4j Server
And wait for Server started at "http://localhost:7474"
Then "http://localhost:7474" should provide the Neo4j REST interface
Then requesting "http://localhost:7474/db/data/ext/" should contain "GremlinPlugin"
Then sending "script=g.V" to "http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script" should contain "node"
Then sending "script=for (i in 1..2){g.v(0);1};1" to "http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script" should contain "1"
Then sending "script=GraphMLReader.inputGraph(g, new URL('https://github.com/tinkerpop/gremlin/raw/master/data/graph-example-1.xml').openStream());g.v(1).outE.inV.name.paths" to "http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script" should contain "1"
\ No newline at end of file
require 'net/http'
require 'time'
Given /^a platform supported by Neo4j$/ do
fail "unsupported platform #{current_platform}" unless current_platform.supported?
end
Given /^Neo4j version based on system property "([^"]*)"$/ do |version_name|
neo4j.version = ENV[version_name]
fail "missing property #{version_name}" if neo4j.version == nil
end
Given /^Neo4j product based on system property "([^"]*)"$/ do |product_name|
neo4j.product = ENV[product_name]
fail "missing property #{product_name}" if neo4j.product == nil
end
When /^dependencies\-zip based on system property "([^\"]*)"$/ do |arg1|
neo4j.dependencies_location = URI.parse(ENV[arg1])
fail "missing property #{arg1}" if neo4j.dependencies_location == nil
end
When /^plugin based on system property "([^\"]*)"$/ do |arg1|
neo4j.plugin_location = URI.parse(ENV[arg1])
fail "missing property #{arg1}" if neo4j.plugin_location == nil
end
Then /^the "([^\"]*)" should exists$/ do |arg1|
fail "#{arg1} does not exists" unless File.exists?(arg1)
end
Given /^set Neo4j Home to "([^"]*)"$/ do |home|
neo4j.home = File.expand_path(home)
neo4j.home = neo4j.home.tr('/', '\\') if (current_platform.windows?)
puts "using neo4j.home "+neo4j.home
ENV["NEO4J_HOME"] = neo4j.home
Dir.mkdir(neo4j.home) unless File.exists?(neo4j.home)
end
Given /^a web site at host "([^"]*)" or system property "([^"]*)"$/ do |host, env_location|
puts "host = #{host}"
puts "env_location = #{env_location}"
puts "env = #{ENV[env_location]}"
if ENV[env_location]
neo4j.download_location = URI.parse(ENV[env_location])
puts "downloading from " + neo4j.download_location.to_s
else
Net::HTTP.get(URI.parse("http://#{host}"))
neo4j.download_location = URI.parse("http://#{host}/#{archive_name}")
puts "downloading from " + neo4j.download_location.to_s
end
end
When /^I download Neo4j \(if I haven't already\)$/ do
transfer_if_newer(neo4j.download_location, archive_name)
end
Then /^the working directory should contain a Neo4j archive$/ do
fail "#{archive_name} does not exists" unless File.exists?(archive_name)
end
When /^I download the plugin \(if I haven't already\)$/ do
transfer_if_newer(neo4j.plugin_location, "plugin.zip");
end
When /^I unpack the archive into Neo4j Home$/ do
if (current_platform.unix?)
untar(File.expand_path(archive_name), neo4j.home)
elsif current_platform.windows?
unzip(File.expand_path(archive_name), neo4j.home)
else
fail 'platform not supported'
end
end
Then /^Neo4j Home should contain a Neo4j Server installation$/ do
if (current_platform.unix?)
fail "file "+neo4j.home+"/bin/neo4j not found" unless File.exists?(neo4j.home+"/bin/neo4j")
elsif (current_platform.windows?)
fail "file "+neo4j.home+"\\bin\\neo4j.bat not found" unless File.exists?(neo4j.home+"\\bin\\neo4j.bat")
else
fail 'platform not supported'
end
end
Then /^the Neo4j version of the installation should be correct$/ do
(Dir.entries(neo4j.home+"/lib") + Dir.entries(neo4j.home+"/system/lib")).each do |lib|
if lib =~ /^neo4j.*\.jar$/
fail lib+" does not contain the Neo4j-version" unless lib =~ /#{neo4j.version}/;
end
end
end
When /^in (Windows|Unix) I will patch the "([^\"]*)" adding "([^\"]*)" to ("[^\"]*")$/ do |platform, config, param, value|
if (platform == "Windows" && current_platform.windows?) || (platform == "Unix" && current_platform.unix?)
File.open(config, "a") do |config_file|
config_file.puts "#{param}=" + eval(value)
end
end
end
Then /^I unzip the "([^\"]*)" into "([^\"]*)"$/ do |archive, target|
unzip(File.expand_path(archive), File.expand_path(target))
end
Then /^copy the "([^\"]*)" to "([^\"]*)"$/ do |source, target|
copy_file(File.expand_path(source), File.expand_path(target))
end
\ No newline at end of file
#Given /^environment variable "([^"]*)" pointing to a Neo(\d+)j Server installation$/ do |arg1, arg2|
# pending # express the regexp above with the code you wish you had
#end
When /^I look in the "([^"]*)" directory under "([^"]*)"$/ do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
Then /^it should have at least (\d+) java file that contains \/extends ServerPlugin\/$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
Then /^it should have at least (\d+) java file that contains \/import javax\.ws\.rs\.Path\/$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
Then /^it should contain a "([^"]*)" jar$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
When /^I install the "([^"]*)" jar from examples\/java\/server\/lib into "([^"]*)"$/ do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
When /^I start the server$/ do
pending # express the regexp above with the code you wish you had
end
When /^I browse the REST API to the database extensions$/ do
pending # express the regexp above with the code you wish you had
end
Then /^they should be non\-empty$/ do
pending # express the regexp above with the code you wish you had
end
Given /^a bash compatible shell$/ do
bash_compatible.should be_true
end
Given /^Java (\d+\.\d+)$/ do |java_version|
bash("java -version 2>&1")
last_stdout.any?{|line| /#{java_version}/ =~ line}.should be_true,
"Java #{java_version} required but not found. Please check your installed Java."
end
Given /^a working directory at relative path "([^"]*)"$/ do |dir_path|
popd
mkdir (dir_path)
pushd(dir_path)
end
Given /^these command\-line tools:$/ do |table|
table.hashes.each do |hash|
bash("#{hash[:command]} #{hash[:version_switch]}")
last_stdout.any?{|line| /#{hash[:version]}/ =~ line}.should be_true,
"#{hash[:command]} version #{hash[:expected_version]} not found"
end
end
Given /^environment variable "([^"]*)" set to "([^"]*)"$/ do |env_var, env_value|
setenv(env_var, env_value)
getenv(env_var).should match(/#{env_value}/)
end
When /^I run these shell commands:$/ do |script|
script.each {|line|
bash(line, :verbose => true)
}
end
When /^I fork this shell command and wait (\d+) seconds:$/ do |seconds, script|
forked_job = fork do
system(script)
end
Process.detach(forked_job)
sleep(seconds.to_i)
end
When /^I run these shell commands in "([^"]*)":$/ do |working_dir, script|
Dir.chdir(working_dir) do
script.each {|line|
bash(line, :verbose => true)
}
end
end
Then /^"([^"]*)" should be an executable$/ do |expected_executable|
test_executable(expected_executable).should be_true,
"neo4j executable not found, or not executable"
end
Then /^"([^"]*)" should exist as a directory$/ do |expected_directory|
test_directory(expected_directory).should be_true,
"missing directory #{expected_directory}"
end
Then /^"([^"]*)" should( not)? exist as a file$/ do |expected_file, negation|
if negation then
test_file(expected_file).should be_false
else
test_file(expected_file).should be_true
end
end
Then /^these commands should succeed:$/ do |script|
script.each {|line|
bash(line, :verbose => true)
last_exit_code.should eql(0),
"Exit code #{last_exit_code}. Check the transcript"
}
end
Given /^"([^"]*)" exists as a directory$/ do |expected_directory|
test_directory(expected_directory).should be_true,
"missing directory #{expected_directory}"
end
Given /^a file named "([^"]*)" with:$/ do |filename, content|
create_file(filename, content)
end
Then /^"([^"]*)" should contain "([^"]*)"$/ do |filename, pattern|
file_contains(filename, Regexp.escape(pattern)).should be_true
end
Given /^Neo4j Server is (not )?running$/ do |negate|
if (current_platform.unix?)
puts `#{neo4j.home}/bin/neo4j status`
$? == (negate == 'not ' ? 256 : 0)
elsif (current_platform.windows?)
puts `#{neo4j.home}\\bin\\wrapper-windows-x86-32.exe -q ..\\conf\\neo4j-wrapper.conf`
puts "result #{$?} "
# fail "failed #{$?} " if $?!= 0
fail "not implemented"
else
fail 'platform not supported'
end
end
When /^I (start|stop) Neo4j Server$/ do |action|
puts "=====> stop/start "
if (current_platform.unix?)
IO.popen("#{neo4j.home}/bin/neo4j #{action}", close_fds=1)
elsif (current_platform.windows?)
Dir.chdir("#{neo4j.home}\\bin")
if (action == "start")
IO.popen("Neo4j.bat install", close_fds=1)
sleep 10
IO.popen("Neo4j.bat start", close_fds=1)
else
IO.popen("Neo4j.bat stop", close_fds=1)
sleep 10
IO.popen("Neo4j.bat remove", close_fds=1)
end
else
fail 'platform not supported'
end
end
When /^wait for Server (started|stopped) at "([^\"]*)"$/ do |state, uri|
i = 0
puts "====> wait"
while i<60 do
puts i
begin
response = Net::HTTP.get_response(URI.parse(uri))
puts response.to_s
break if (response.code.to_i == 200) && state == "started"
rescue Exception=>e
puts e.to_s
break if (state == "stopped")
end
sleep 5
i += 1
end
end
Then /^"([^"]*)" should (not)? ?provide the Neo4j REST interface$/ do |uri, negate|
begin
response = Net::HTTP.get_response(URI.parse(uri))
rescue Exception=>e
fail "REST-interface is not running #{e}" if e && negate != 'not'
end
fail 'REST-interface is not running' if negate == nil && response && response.code.to_i != 200
fail 'REST-interface is running' if negate == 'not' && response && response.code.to_i == 200
end
Then /^requesting "([^\"]*)" should contain "([^\"]*)"$/ do |uri, result|
response = Net::HTTP.get_response(URI.parse(uri))
fail "invalid response code #{response.code.to_i}" unless response || response.code.to_i == 200
response_body = response.body
puts response_body
fail "expected '#{result}' not found in '#{response_body}'" unless response_body =~ /#{result}/
end
Then /^sending "([^\"]*)" to "([^\"]*)" should contain "([^\"]*)"$/ do |content, uri, result|
location = URI.parse(uri)
puts location
puts "parameters: #{content}"
server = Net::HTTP.new(location.host, location.port ? location.port : 80)
response = server.request_post(location.path, content)
fail "invalid response code #{response.code.to_i}" unless response || response.code.to_i == 200
response_body = response.body
puts response_body
fail "expected '#{result}' not found in '#{response_body}'" unless response_body =~ /#{result}/
end
Then /^updating "(.*)" to "(.*)" should have a response of "(.*)"$/ do |content, uri, response_code|
location = URI.parse(uri)
puts location
server = Net::HTTP.new(location.host, location.port ? location.port : 80)
response = server.request_put(location.path, content, {'Content-Type' => 'application/json'})
fail "invalid response code #{response.code.to_i}" unless response || response.code.to_i == response_code
response_body = response.body
puts response_body
end
\ No newline at end of file
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
require 'features/support/shell_helpers'
require 'features/support/network_helpers'
require 'features/support/platform_helpers'
require 'features/support/neo4j_helpers'
World(ShellHelpers, NetworkHelpers, PlatformHelpers, Neo4JHelpers)
After do |scenario|
# Do something after each scenario.
# The +scenario+ argument is optional, but
# if you use it, you can inspect status with
# the #failed?, #passed? and #exception methods.
if neo4j.home && current_platform.unix?
`#{neo4j.home}/bin/neo4j status`
if ($? == 0) ## is running
`#{neo4j.home}/bin/neo4j stop`
end
end
if neo4j.home && current_platform.windows?
IO.popen("#{neo4j.home}\\bin\\Neo4j.bat stop")
sleep 12
IO.popen("#{neo4j.home}\\bin\\Neo4j.bat remove")
end
end
module Neo4JHelpers
attr_accessor :neo4j
def neo4j
unless (@neo4j)
@neo4j= Neo4jEnvironment.new
end
@neo4j
end
def archive_name
"neo4j-" + @neo4j.product + "-" + @neo4j.version + "-" + current_platform.type + "."+current_platform.extension
end
class Neo4jEnvironment
attr_accessor :version, :download_location, :plugin_location, :home, :product
end
end
module NetworkHelpers
require 'socket'
require 'timeout'
def is_port_open?(ip, port)
begin
Timeout::timeout(1) do
begin
s = TCPSocket.new(ip, port)
s.close
return true
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
return false
end
end
rescue Timeout::Error
end
false
end
def copy_file(source, target)
puts "copy '#{source}' -> '#{target}'"
File.open(source, "r") do |src|
open(target, "wb") do |file|
while buf = src.read(2048)
file.write(buf)
end
end
end
end
def transfer_if_newer(location, target)
puts "transfer_if_newer(#{location},#{target})"
if (location.scheme == "http") then
server = Net::HTTP.new(location.host, 80)
head = server.head(location.path)
server_time = Time.httpdate(head['last-modified'])
if (!File.exists?(target) || server_time != File.mtime(target))
puts target+" missing or newer version as on #{location} - downloading"
server.request_get(location.path) do |res|
open(target, "wb") do |file|
res.read_body do |segment|
file.write(segment)
end
end
end
File.utime(0, server_time, target)
else
puts target+" not modified - download skipped"
end
elsif (location.scheme == "file") then
copy_file(location.path, target)
else
raise 'unsupported schema ' + location
end
end
def fix_file_sep(file)
file.tr('/', '\\')
end
def unzip(full_archive_name, target)
if (current_platform.unix?)
exec_wait("unzip -o #{full_archive_name} -d #{target}")
elsif (current_platform.windows?)
exec_wait("cmd /c " + fix_file_sep(File.expand_path("../../support/unzip.vbs", __FILE__)) + " " +
fix_file_sep(full_archive_name) + " " + target)
else
raise 'platform not supported'
end
end
def exec_wait(cmd)
puts "exec: '#{cmd}'"
puts `#{cmd}`
raise "execution failed(#{$?})" unless $?.to_i == 0
end
def untar(archive, target)
if (current_platform.unix?)
pushd target
exec_wait("tar xzf #{archive} --strip-components 1")
popd
else
raise 'platform not supported'
end
end
end
module PlatformHelpers
require 'rbconfig'
class Platform
attr_reader :type, :extension
def initialize(type, extension)
@type = type
@extension = extension
end
def supported?
@extension != nil
end
def windows?
@type == "windows"
end
def unix?
@type == "unix"
end
def unknown?
@type == "unknown"
end
end
def current_platform
platform = RbConfig::CONFIG['target_os']
if platform =~ /win32/
Platform.new('windows', 'zip')
elsif platform =~ /linux/ || platform =~ /darwin/ || platform =~ /freebsd/
Platform.new('unix', 'tar.gz')
else
Platform.new('unknown', nil)
end
end
end
module ShellHelpers
require 'fileutils'
@@dir_stack = []
def init_dir(dir_path)
FileUtils.rm_rf(dir_path)
Dir.mkdir(dir_path) if !File.directory?(dir_path)
end
def mkdir(dir_path)
Dir.mkdir(dir_path) if !File.directory?(dir_path)
end
def working_dir
@working_dir
end
def working_dir=(dir_path)
@working_dir = dir_path
end
# not a very robust check for compatibility
def bash_compatible
shell = `sh --version`
return ($?.to_i == 0)
end
def setenv(varname, value)
ENV["#{varname}"] = "#{value}"
end
def getenv(varname)
bash("echo $#{varname}")
return @stdout
end
def test_executable(executable_path)
bash("[[ -x #{executable_path} ]]")
return (@exit_code == 0)
end
def test_directory(dir_path)
bash("[[ -d #{dir_path} ]]")
return (@exit_code == 0)
end
def test_file(dir_path)
bash("[[ -f #{dir_path} ]]")
return (@exit_code == 0)
end
def bash(cmdline, verbose = false)
puts "$ " + cmdline if (verbose)
@stdout = `#{cmdline}`
@exit_code = $?.to_i
end
def last_stdout
return @stdout
end
def last_exit_code
return @exit_code
end
def create_file(file_name, contents)
file_path = File.join(file_name)
File.open(file_path, "w") { |f| f << contents }
end
def file_contains(file_name, pattern)
r = Regexp.new(pattern)
File.open( file_name ).any? {|line|
r =~ line
}
end
def pushd(path)
@@dir_stack.push(Dir.getwd)
Dir.chdir(path)
end
def popd
Dir.chdir(@@dir_stack.pop) if !@@dir_stack.empty?
end
end
Set args = WScript.Arguments
Set s= CreateObject("Shell.Application")
s.NameSpace(args.Item(1)).CopyHere s.NameSpace(args.Item(0)).Items.Item(0).GetFolder.Items, 256+16
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.neo4j.build</groupId>
<artifactId>parent-pom</artifactId>
<version>25.U1</version>
<relativePath />
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.neo4j.server.plugin</groupId>
<artifactId>neo4j-gremlin-plugin</artifactId>
<packaging>jar</packaging>
<version>1.5.4-SNAPSHOT</version>
<name>neo4j-gremlin-plugin</name>
<properties>
<!-- Jar Versions -->
<spring.version>3.0.4.RELEASE</spring.version>
<jackson.version>1.5.2</jackson.version>
<cxf.version>2.3.1</cxf.version>
<servlet-api.version>2.5</servlet-api.version>
<neo4j.version>1.5.4-SNAPSHOT</neo4j.version>
<blueprints.version>1.0</blueprints.version>
<jersey.server.version>1.6</jersey.server.version>
<license-text.header>GPL-3-header.txt</license-text.header>
<licensesVersion>7</licensesVersion>
<currentYear>2012</currentYear>
</properties>
<inceptionYear>2002</inceptionYear>
<licenses>
<license>
<name>GNU General Public License, Version 3</name>
<url>http://www.gnu.org/licenses/gpl-3.0-standalone.html</url>
<comments>The software ("Software") developed and owned by Network Engine for
Objects in Lund AB (referred to in this notice as "Neo Technology") is
licensed under the GNU GENERAL PUBLIC LICENSE Version 3 to all third
parties and that license is included below.
However, if you have executed an End User Software License and Services
Agreement or an OEM Software License and Support Services Agreement, or
another commercial license agreement with Neo Technology or one of its
affiliates (each, a "Commercial Agreement"), the terms of the license in
such Commercial Agreement will supersede the GNU GENERAL PUBLIC LICENSE
Version 3 and you may use the Software solely pursuant to the terms of
the relevant Commercial Agreement.
</comments>
</license>
</licenses>
<scm>
<connection>scm:git:git://github.com/neo4j/gremlin-plugin.git</connection>
<developerConnection>scm:git:git@github.com:neo4j/gremlin-plugin.git</developerConnection>
<url>https://github.com/neo4j/gremlin-plugin</url>
</scm>
<dependencies>
<!-- Neo4j Dependencies -->
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>${neo4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>${neo4j.version}</version>
<type>test-jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>${neo4j.version}</version>
<classifier>static-web</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
<version>${neo4j.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.server.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.server.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>${neo4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>server-api</artifactId>
<version>${neo4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-neo4j-graph</artifactId>
<version>${blueprints.version}</version>
<scope>provided</scope>
</dependency>
<!-- Jackson Dependencies -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>${jackson.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>${jackson.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>${jackson.version}</version>
<scope>provided</scope>
</dependency>
<!--end jackson dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-graphviz</artifactId>
<version>${neo4j.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/webapp</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>data</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/server-plugin.xml</descriptor>
<descriptor>src/main/assembly/docs-assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- this is used for inheritance merges -->
<phase>package</phase>
<!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- for license headers -->
<plugin>
<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.neo4j.maven</groupId>
<artifactId>licenses</artifactId>
<version>${licensesVersion}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>check-licenses</id>
<!-- fail as early as possible -->
<phase>initialize</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<strictCheck>true</strictCheck>
<header>${license-text.header}</header>
<includes>
<include>src/**/*.java</include>
<include>src/**/*.js</include>
<include>src/**/*.scala</include>
<include>src/**/*.xml</include>
</includes>
<excludes>
<exclude>**/lib/*.js</exclude>
<exclude>**/lib/**/*.js</exclude>
<exclude>**/javascript/vend/**</exclude>
</excludes>
<mapping>
<scala>JAVADOC_STYLE</scala>
</mapping>
<properties>
<inceptionYear>${project.inceptionYear}</inceptionYear>
<currentYear>${currentYear}</currentYear>
</properties>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>neo4j-build</id>
<name>neo4j.org repository</name>
<url>http://m2.neo4j.org/content/repositories/everything/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<distributionManagement>
<site>
<id>neo4j-site</id>
<url>scpexe://components.neo4j.org/home/neo/components/${project.artifactId}/${project.version}</url>
</site>
</distributionManagement>
</project>
export NEO4J_HOME=target/neo4j_home
export NEO4J_PRODUCT=community
export NEO4J_VERSION=1.4-SNAPSHOT
export DOWNLOAD_LOCATION=http://builder.neo4j.org/guestAuth/repository/download/bt65/.lastSuccessful/standalone/neo4j-community-1.4-SNAPSHOT-unix.tar.gz
export DOWNLOAD_PLUGIN_LOCATION=file:/Users/peterneubauer/code/neo/neo4j-gremlin-plugin/target/neo4j-gremlin-plugin-0.1-SNAPSHOT-server-plugin.zip
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2002-2012 "Neo Technology,"
Network Engine for Objects in Lund AB [http://neotechnology.com]
This file is part of Neo4j.
Neo4j is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key id="weight" for="edge" attr.name="weight" attr.type="float"/>
<key id="name" for="node" attr.name="name" attr.type="string"/>
<key id="age" for="node" attr.name="age" attr.type="int"/>
<key id="lang" for="node" attr.name="lang" attr.type="string"/>
<graph id="G" edgedefault="directed">
<node id="1">
<data key="name">I</data>
</node>
<node id="2">
<data key="name">you</data>
</node>
<node id="3">
<data key="name">him</data>
</node>
<edge id="1" source="1" target="2" label="know">
<data key="weight">0.5</data>
</edge>
<edge id="2" source="1" target="3" label="know">
<data key="weight">0.8</data>
</edge>
</graph>
</graphml>
\ No newline at end of file
[[gremlin-plugin]]
Gremlin Plugin
==============
image::gremlin-logo.png[]
http://gremlin.tinkerpop.com[Gremlin] is a Groovy based Graph Traversal Language. It provides a very expressive way of explicitly scripting traversals through a Neo4j graph.
The Neo4j Gremlin Plugin provides an endpoint to send Gremlin scripts to the Neo4j Server.
The scripts are executed on the server database and the results are returned as Neo4j Node and Relationship representations.
This keeps the types throughout the REST API consistent.
The results are quite verbose when returning Neo4j +Node+,
+Relationship+ or +Graph+ representations.
On the other hand, just return properties like in the <<rest-api-send-a-gremlin-script---json-encoded-with-table-results>>
example for responses tailored to specific needs.
:leveloffset: 1
include::send-a-gremlin-script---url-encoded.txt[]
include::load-a-sample-graph.txt[]
include::sort-a-result-using-raw-groovy-operations.txt[]
include::send-a-gremlin-script---json-encoded-with-table-results.txt[]
include::set-script-variables.txt[]
include::send-a-gremlin-script-with-variables-in-a-json-map.txt[]
include::return-paths-from-a-gremlin-script.txt[]
include::send-an-arbitrary-groovy-script---lucene-sorting.txt[]
include::emit-a-sample-graph.txt[]
include::hyperedges---find-user-roles-in-groups.txt[]
include::group-count.txt[]
include::collect-multiple-traversal-results.txt[]
include::collaborative-filtering.txt[]
include::chunking-and-offsetting-in-gremlin.txt[]
include::modify-the-graph-while-traversing.txt[]
<!--
Copyright (c) 2002-2012 "Neo Technology,"
Network Engine for Objects in Lund AB [http://neotechnology.com]
This file is part of Neo4j.
Neo4j is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<assembly>
<id>docs</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>target/docs/rest-api</directory>
<outputDirectory>/dev/plugins/gremlin</outputDirectory>
</fileSet>
<fileSet>
<directory>src/docs</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
<!--
Copyright (c) 2002-2012 "Neo Technology,"
Network Engine for Objects in Lund AB [http://neotechnology.com]
This file is part of Neo4j.
Neo4j is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!-- Copyright (c) 2002-2012 "Neo Technology," Network Engine for Objects in Lund AB [http://neotechnology.com] This file is part of Neo4j. Neo4j is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. -->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>server-plugin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
\ No newline at end of file
/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.server.plugin.gremlin;
import java.util.concurrent.atomic.AtomicInteger;
class CountingEngineReplacementDecision implements EngineReplacementDecision {
private final AtomicInteger executionCount = new AtomicInteger();
private final int maxExecutionCount;
public CountingEngineReplacementDecision(int maxExecutionCount) {
this.maxExecutionCount = maxExecutionCount;
}
@Override
public void beforeExecution(String script) {
executionCount.incrementAndGet();
}
@Override
public boolean mustReplaceEngine() {
if (executionCount.get() < maxExecutionCount) return false;
executionCount.set(0);
return true;
}
}
/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.server.plugin.gremlin;
public interface EngineReplacementDecision {
boolean mustReplaceEngine();
void beforeExecution(String script);
}
/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.server.plugin.gremlin;
import java.util.Map;
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.server.plugins.Description;
import org.neo4j.server.plugins.Name;
import org.neo4j.server.plugins.Parameter;
import org.neo4j.server.plugins.PluginTarget;
import org.neo4j.server.plugins.ServerPlugin;
import org.neo4j.server.plugins.Source;
import org.neo4j.server.rest.repr.Representation;
import org.neo4j.server.rest.repr.ValueRepresentation;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph;
/* This is a class that will represent a server side
* Gremlin plugin and will return JSON
* for the following use cases:
* Add/delete vertices and edges from the graph.
* Manipulate the graph indices.
* Search for elements of a graph.
* Load graph data from a file or URL.
* Make use of JUNG algorithms.
* Make use of SPARQL queries over OpenRDF-based graphs.
* and much, much more.
*/
@Description( "A server side Gremlin plugin for the Neo4j REST server" )
public class GremlinPlugin extends ServerPlugin
{
private final String g = "g";
private volatile ScriptEngine engine;
private final EngineReplacementDecision engineReplacementDecision = new CountingEngineReplacementDecision(
500 );
private final GremlinToRepresentationConverter gremlinToRepresentationConverter = new GremlinToRepresentationConverter();
private ScriptEngine createQueryEngine()
{
return new ScriptEngineManager().getEngineByName( "gremlin" );
}
@Name( "execute_script" )
@Description( "execute a Gremlin script with 'g' set to the Neo4jGraph and 'results' containing the results. Only results of one object type is supported." )
@PluginTarget( GraphDatabaseService.class )
public Representation executeScript(
@Source final GraphDatabaseService neo4j,
@Description( "The Gremlin script" ) @Parameter( name = "script", optional = false ) final String script,
@Description( "JSON Map of additional parameters for script variables" ) @Parameter( name = "params", optional = true ) final Map params )
{
try
{
engineReplacementDecision.beforeExecution( script );
final Bindings bindings = createBindings( neo4j, params );
final Object result = engine().eval( script, bindings );
return gremlinToRepresentationConverter.convert( result );
}
catch ( final ScriptException e )
{
return ValueRepresentation.string( e.getMessage() );
}
}
private Bindings createBindings( GraphDatabaseService neo4j, Map params )
{
final Bindings bindings = createInitialBinding( neo4j );
if ( params != null )
{
bindings.putAll( params );
}
return bindings;
}
private Bindings createInitialBinding( GraphDatabaseService neo4j )
{
final Bindings bindings = new SimpleBindings();
final Neo4jGraph graph = new Neo4jGraph( neo4j );
bindings.put( g, graph );
return bindings;
}
private ScriptEngine engine()
{
if ( this.engine == null
|| engineReplacementDecision.mustReplaceEngine() )
{
this.engine = createQueryEngine();
}
return this.engine;
}
public Representation getRepresentation( final Object data )
{
return gremlinToRepresentationConverter.convert( data );
}
}
/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.server.plugin.gremlin;
import java.util.ArrayList;
import java.util.List;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.server.rest.repr.GremlinTableRepresentation;
import org.neo4j.server.rest.repr.ListRepresentation;
import org.neo4j.server.rest.repr.NodeRepresentation;
import org.neo4j.server.rest.repr.RelationshipRepresentation;
import org.neo4j.server.rest.repr.Representation;
import org.neo4j.server.rest.repr.RepresentationType;
import org.neo4j.server.rest.repr.ValueRepresentation;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jEdge;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jVertex;
import com.tinkerpop.pipes.util.Table;
public class GremlinToRepresentationConverter {
public GremlinToRepresentationConverter() {
}
public Representation convert(final Object data) {
if (data instanceof Table) {
return new GremlinTableRepresentation((Table) data);
}
if (data instanceof Iterable) {
return getListRepresentation((Iterable) data);
}
return getSingleRepresentation(data);
}
Representation getListRepresentation(Iterable data) {
final List<Representation> results = convertValuesToRepresentations(data);
return new ListRepresentation(getType(results), results);
}
List<Representation> convertValuesToRepresentations(Iterable data) {
final List<Representation> results = new ArrayList<Representation>();
for (final Object value : data) {
if(value instanceof Iterable) {
convertValuesToRepresentations( (Iterable) value );
}
final Representation representation = getSingleRepresentation(value);
results.add(representation);
}
return results;
}
RepresentationType getType(List<Representation> representations) {
if (representations == null || representations.isEmpty()) return RepresentationType.STRING;
return representations.get(0).getRepresentationType();
}
Representation getSingleRepresentation(Object result) {
if (result == null) return ValueRepresentation.string("null");
if (result instanceof Neo4jVertex) {
return new NodeRepresentation(((Neo4jVertex) result).getRawVertex());
} else if (result instanceof Neo4jEdge) {
return new RelationshipRepresentation(((Neo4jEdge) result).getRawEdge());
} else if (result instanceof Node) {
return new NodeRepresentation((Node) result);
} else if (result instanceof Relationship) {
return new RelationshipRepresentation( (Relationship) result);
} else if (result instanceof Neo4jGraph) {
return ValueRepresentation.string(((Neo4jGraph) result).getRawGraph().toString());
} else if (result instanceof Double || result instanceof Float) {
return ValueRepresentation.number(((Number) result).doubleValue());
} else if (result instanceof Long) {
return ValueRepresentation.number(((Long) result).longValue());
} else if (result instanceof Integer) {
return ValueRepresentation.number(((Integer) result).intValue());
} else {
return ValueRepresentation.string(result.toString());
}
}
}
\ No newline at end of file
/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.server.plugin.gremlin;
import java.util.HashSet;
import java.util.Set;
public class ScriptCountingEngineReplacementDecision implements EngineReplacementDecision {
private final Set<String> scripts=new HashSet<String>();
private final int maxScriptCount;
public ScriptCountingEngineReplacementDecision(int maxScriptCount) {
this.maxScriptCount = maxScriptCount;
}
@Override
public boolean mustReplaceEngine() {
if (scripts.size() < maxScriptCount) return false;
scripts.clear();
return true;
}
@Override
public void beforeExecution(String script) {
scripts.add(script);
}
}
/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.server.rest.repr;
import java.util.ArrayList;
import java.util.List;
import org.neo4j.server.plugin.gremlin.GremlinToRepresentationConverter;
import com.tinkerpop.pipes.util.Table;
import com.tinkerpop.pipes.util.Table.Row;
public class GremlinTableRepresentation extends ObjectRepresentation
{
private final Table queryResult;
private final GremlinToRepresentationConverter converter = new GremlinToRepresentationConverter();
public GremlinTableRepresentation(Table result)
{
super( RepresentationType.STRING );
this.queryResult = result;
}
@Mapping( "columns" )
public Representation columns()
{
return ListRepresentation.string( queryResult.getColumnNames() );
}
@Mapping( "data" )
public Representation data()
{
List<Representation> rows = new ArrayList<Representation>();
for ( Row row : queryResult )
{
rows.add( new ListRepresentation( "row", convertRow(row)) );
}
return new ListRepresentation( "data", rows );
}
private List<Representation> convertRow(Row row) {
List<Representation> fields = new ArrayList<Representation>();
for ( String column : queryResult.getColumnNames() )
{
final Object fieldValue = row.getColumn(column);
Representation fieldRepresentation = converter.convert(fieldValue);
fields.add( fieldRepresentation );
}
return fields;
}
}
org.neo4j.server.plugin.gremlin.GremlinPlugin
\ No newline at end of file
/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.server.plugin.gremlin;
import com.tinkerpop.blueprints.pgm.Graph;
import com.tinkerpop.blueprints.pgm.Vertex;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph;
import junit.framework.Assert;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.neo4j.graphdb.Transaction;
import org.neo4j.server.rest.repr.OutputFormat;
import org.neo4j.server.rest.repr.Representation;
import org.neo4j.server.rest.repr.formats.JsonFormat;
import org.neo4j.test.ImpermanentGraphDatabase;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertTrue;
public class GremlinPluginTest
{
private static ImpermanentGraphDatabase neo4j = null;
private static GremlinPlugin plugin = null;
private static OutputFormat json = null;
private static JSONParser parser = new JSONParser();
@BeforeClass
public static void setUpBeforeClass() throws Exception
{
json = new OutputFormat( new JsonFormat(),
new URI( "http://localhost/" ), null );
neo4j = new ImpermanentGraphDatabase( "target/db" );
plugin = new GremlinPlugin();
Graph graph = new Neo4jGraph( neo4j );
graph.removeVertex( graph.getVertex( 0 ) );
Vertex marko = graph.addVertex( "1" );
marko.setProperty( "name", "marko" );
marko.setProperty( "age", 29 );
Vertex vadas = graph.addVertex( "2" );
vadas.setProperty( "name", "vadas" );
vadas.setProperty( "age", 27 );
Vertex lop = graph.addVertex( "3" );
lop.setProperty( "name", "lop" );
lop.setProperty( "lang", "java" );
Vertex josh = graph.addVertex( "4" );
josh.setProperty( "name", "josh" );
josh.setProperty( "age", 32 );
Vertex ripple = graph.addVertex( "5" );
ripple.setProperty( "name", "ripple" );
ripple.setProperty( "lang", "java" );
Vertex peter = graph.addVertex( "6" );
peter.setProperty( "name", "peter" );
peter.setProperty( "age", 35 );
graph.addEdge( "7", marko, vadas, "knows" ).setProperty( "weight", 0.5f );
graph.addEdge( "8", marko, josh, "knows" ).setProperty( "weight", 1.0f );
graph.addEdge( "9", marko, lop, "created" ).setProperty( "weight", 0.4f );
graph.addEdge( "10", josh, ripple, "created" ).setProperty( "weight",
1.0f );
graph.addEdge( "11", josh, lop, "created" ).setProperty( "weight", 0.4f );
graph.addEdge( "12", peter, lop, "created" ).setProperty( "weight",
0.2f );
}
private String exampleURI = "https://github.com/tinkerpop/gremlin/raw/master/data/graph-example-1.xml";
@After
public void tearDown() throws Exception
{
}
@Test
public void testExecuteScriptVertex() throws Exception
{
JSONObject object = (JSONObject) parser.parse( json.format( GremlinPluginTest.executeTestScript( "g.v(1)", null) ) );
Assert.assertEquals( 29l,
( (JSONObject) object.get( "data" ) ).get( "age" ) );
Assert.assertEquals( "marko",
( (JSONObject) object.get( "data" ) ).get( "name" ) );
}
@Test
public void testReturnTable() throws Exception
{
assertTrue(json.format( GremlinPluginTest.executeTestScript( ""+
"t = new Table();" +
"g.v(1).out('knows').as('friends').table(t)>> -1;t;", null) ).contains("josh"));
}
@Test
public void testExecuteScriptVertices() throws Exception
{
JSONArray array = (JSONArray) parser.parse( json.format( GremlinPluginTest.executeTestScript( "g.V", null) ) );
List<String> ids = new ArrayList<String>( Arrays.asList( "1", "2", "3",
"4", "5", "6" ) );
Assert.assertEquals( array.size(), 6 );
for ( Object object : array )
{
String self = (String) ( (JSONObject) object ).get( "self" );
String id = self.substring( self.lastIndexOf( "/" ) + 1 );
ids.remove( id );
String name = (String) ( (JSONObject) ( (JSONObject) object ).get( "data" ) ).get( "name" );
if ( id.equals( "1" ) )
{
Assert.assertEquals( name, "marko" );
}
else if ( id.equals( "2" ) )
{
Assert.assertEquals( name, "vadas" );
}
else if ( id.equals( "3" ) )
{
Assert.assertEquals( name, "lop" );
}
else if ( id.equals( "4" ) )
{
Assert.assertEquals( name, "josh" );
}
else if ( id.equals( "5" ) )
{
Assert.assertEquals( name, "ripple" );
}
else if ( id.equals( "6" ) )
{
Assert.assertEquals( name, "peter" );
}
else
{
Assert.assertTrue( false );
}
}
Assert.assertEquals( ids.size(), 0 );
}
@Test
public void testExecuteScriptEdges() throws Exception
{
JSONArray array = (JSONArray) parser.parse( json.format( GremlinPluginTest.executeTestScript( "g.E", null) ) );
List<String> ids = new ArrayList<String>( Arrays.asList( "0", "1", "2",
"3", "4", "5" ) );
Assert.assertEquals( array.size(), 6 );
for ( Object object : array )
{
String self = (String) ( (JSONObject) object ).get( "self" );
String id = self.substring( self.lastIndexOf( "/" ) + 1 );
ids.remove( id );
Double weight = (Double) ( (JSONObject) ( (JSONObject) object ).get( "data" ) ).get( "weight" );
Assert.assertNotNull( weight );
Assert.assertTrue( weight > 0.1 );
}
Assert.assertEquals( ids.size(), 0 );
}
@Test
public void testExecuteScriptGraph() throws Exception
{
String ret = (String) parser.parse( json.format( GremlinPluginTest.executeTestScript( "g", null) ) );
Assert.assertEquals( ret, "ImpermanentGraphDatabase [target/db]" );
}
@Test
public void testExecuteScriptLong() throws Exception
{
Assert.assertEquals(
1L,
parser.parse( json.format( GremlinPluginTest.executeTestScript( "1", null) ) ) );
}
@Test
public void testExecuteScriptLongs()
{
Assert.assertEquals(
"[ 1, 2, 5, 6, 8 ]",
json.format( GremlinPluginTest.executeTestScript( "[1,2,5,6,8]", null) ) );
}
@Test
public void testExecuteScriptNull()
{
Assert.assertEquals(
"\"null\"",
json.format( GremlinPluginTest.executeTestScript( "for(i in 1..2){g.v(0)}", null) ) );
}
@Test
public void testExecuteScriptParams() throws ParseException
{
Assert.assertEquals(
"1",
json.format( GremlinPluginTest.executeTestScript( "x", (Map)parser.parse( "{\"x\" : 1}")) ) );
}
@Test
public void testExecuteScriptEmptyParams() throws ParseException
{
Assert.assertEquals(
"1",
json.format( GremlinPluginTest.executeTestScript( "1", (Map)parser.parse( "{}")) ) );
}
@Test
public void testMultilineScriptWithLinebreaks()
{
Assert.assertEquals( "2",
json.format( GremlinPluginTest.executeTestScript( "1;\n2", null) ) );
}
@Test
public void testMultiThread()
{
for ( int i = 0; i < 250; i++ )
{
final int x = i;
new Thread()
{
public void run()
{
Assert.assertEquals(
x + "",
json.format( GremlinPluginTest.executeTestScript( "x="
+ x
+ "; x", null) ) );
}
}.start();
}
}
private static Representation executeTestScript(final String script, Map params)
{
Transaction tx = null;
try
{
tx = neo4j.beginTx();
return plugin.executeScript( neo4j, script, params );
}
finally
{
tx.success();
tx.finish();
}
}
@Test
public void testExecuteScriptGetVerticesBySpecifiedName() throws Exception
{
JSONObject object = (JSONObject) parser.parse( json.format( GremlinPluginTest.executeTestScript( "g.V[[name:'marko']] >> 1", null) ) );
Assert.assertEquals(
( (JSONObject) object.get( "data" ) ).get( "name" ), "marko" );
Assert.assertEquals(
( (JSONObject) object.get( "data" ) ).get( "age" ), 29l );
String self = (String) ( (JSONObject) object ).get( "self" );
Assert.assertEquals( self.substring( self.lastIndexOf( "/" ) + 1 ), "1" );
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册