neo4jr-social 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Matthew Deiters
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,88 @@
1
+ = neo4jr-social
2
+
3
+ Neo4jr-Social is a self contained HTTP REST + JSON interface to the graph database Neo4j. Neo4jr-Social supports simple dynamic node creation, building relationships between nodes and also includes a few common social networking queries out of the box (i.e. linkedin degrees of seperation and facebook friend suggestion) with more to come. Think of Neo4jr-Social is to Neo4j like Solr is to Lucene.
4
+
5
+ Neo4jr-Social was built in JRuby but is language agnostic and is designed to run under Jetty or Tomcat.
6
+
7
+ = Getting Started
8
+
9
+ === Prerequisites
10
+ * Java
11
+ * JRuby: http://jruby.org
12
+
13
+ === Installing
14
+ * Install Ruby Gem: json_pure
15
+ jgem install json_pure
16
+ * Install Ruby Gem: sinatra
17
+ jgem install sinatra
18
+ * Install Ruby Gem: neo4jr-simple
19
+ jgem install neo4jr-simple
20
+ * Install Ruby Gem: neo4jr-social
21
+ jgem install neo4jr-simple
22
+
23
+ === Starting Neo4jr-Social
24
+
25
+ After installing the above gems, an executable 'start-neo4jr-social' should be in your path. This will start the service and the database and listen for HTTP requests on localhost at port 8988:
26
+
27
+ start-neo4jr-social -p8988
28
+
29
+ You can also start the service and specify the directory of where the neo4j database is stored or where to create a new database. If you omit this setting a database will be created in your tmp directory and destroyed when you shutdown the server.
30
+
31
+ start-neo4jr-social -p8988 -dsome_relative_or_absolute_directory
32
+
33
+ Run start-neo4jr-social --help to see all options
34
+
35
+ === API Overview
36
+ All results returned will be in JSON
37
+
38
+ ==== GET /info
39
+ Returns details about the Neo4jr database like the location of the database and the number of nodes.
40
+
41
+ ==== GET /nodes
42
+ Returns all nodes in the database. Use this method with caution, this could crash your server if you have a database with more then a few thousand nodes.
43
+
44
+ ==== POST /nodes
45
+ Creates a new node in the neo4jr database. Any parameters based in the body of the POST will be treated as properties for the node and will be stored in the database.
46
+
47
+ ==== GET /nodes/:node_id
48
+ Returns the properties for the specified node, where :node_id is the numeric id for the node
49
+
50
+ ==== PUT /nodes/:node_id
51
+ Updates the properties of the specified node, where :node_id is the numeric id for the node. Any parameters pased in the body of the PUT will be treated as properties for the node. If you add a new parameters (i.e. age=4) which previously were not on the node, neo4jr-social will still add that property to the node.
52
+
53
+ ==== DELETE /nodes/:node_id
54
+ Deletes the specified node, where :node_id is the numeric id for the node.
55
+
56
+ ==== POST /nodes/:node_id/relationships
57
+ Creates a relations for the specified node, where :node_id is the numeric id for the node. This is how you designate how two nodes are related to each other.
58
+ * Required: to - this is the node id of the node you want to make a relationship to. This is a one-way relationship. If you want both nodes to be related to each other you will need to make individual POSTs for each direction of the relationship.
59
+ * Required: type - this is the type of the relationship, i.e. 'friends'. This can be any string that is sensible in your domain.
60
+ * Optional: Any other parameters you supply in the body of the POST will be added as properties to the relationship. For example if you were making 'friend' relationships and wanted to add a date since the friendship started you could pass a 'since' parameter in the POST.
61
+
62
+ ==== GET /nodes/:node_id/relationships
63
+ Returns relationships to other nodes for the specified node, where :node_id is the numeric id for the node.
64
+ * Optional: type - Specify a type if only certain relationships are of interest
65
+
66
+ ==== GET /nodes/:node_id/path
67
+ This returns all the ways two nodes are connected to each other and is similar to LinkedIn's degrees of separation.
68
+ * Required: to - the id of the node that your trying to find a path to from the starting node, :node_id
69
+ * Required: type - the type of relationships between nodes to follow
70
+ * Optional: depth - maximum degrees of separation to find, the default is 2 degrees. Note: There may be performance impacts if this number is to high.
71
+ * Optional: direction - What direction of relationships to follow, the default is 'both'
72
+
73
+ ==== GET /nodes/:node_id/recommendations
74
+ This returns node suggestions for the given :node_id. This is similar to facebook friend suggestions where your friend's friends that your not friends with are suggested to you.
75
+ * Required: type - the type of relationships between nodes to follow
76
+ * Optional: level - the degree of separation that you want recommendations for, the default is 1 degree away which is similar to facebook's behavior
77
+
78
+ == Contributors
79
+
80
+ ====Matthew Deiters
81
+ * Twitter : http://twitter.com/mdeiters
82
+ * GitHub : https://github.com/mdeiters
83
+ * LinkedIn : http://www.linkedin.com/in/matthewdeiters
84
+ * Blog : http://www.theagiledeveloper.com
85
+
86
+ == Copyright
87
+
88
+ Copyright (c) 2009 Matthew Deiters. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,70 @@
1
+ # http://wiki.github.com/technicalpickles/jeweler/customizing-your-projects-gem-specification
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "neo4jr-social"
10
+ gem.summary = %Q{A self-containted and lightweight REST interface to Neo4j using JRuby.}
11
+ gem.description = %Q{A self-containted and lightweight REST interface to Neo4j using JRuby.}
12
+ gem.description = %Q{A self-containted lightweight REST interface to Neo4j using JRuby }
13
+ gem.email = "matthew_deiters@mckinsey.com"
14
+ gem.homepage = "http://github.com/mdeiters/neo4jr-social"
15
+ gem.authors = ["Matthew Deiters"]
16
+ gem.add_development_dependency "rspec", ">= 1.2.9"
17
+ gem.add_development_dependency "rest-client"
18
+ gem.add_dependency 'neo4jr-simple'
19
+ gem.add_dependency 'sinatra'
20
+ gem.add_dependency 'json_pure'
21
+
22
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
23
+ end
24
+ Jeweler::GemcutterTasks.new
25
+ rescue LoadError
26
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
27
+ end
28
+
29
+ require 'spec/rake/spectask'
30
+ Spec::Rake::SpecTask.new(:spec) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.spec_files = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
36
+ spec.libs << 'lib' << 'spec'
37
+ spec.pattern = 'spec/**/*_spec.rb'
38
+ spec.rcov = true
39
+ end
40
+
41
+ task :spec => :check_dependencies
42
+
43
+ task :default => :spec
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "neo4jr-social #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
54
+
55
+ task :warify do
56
+ commands = ['rm -rf tmp']
57
+ commands << 'warble'
58
+ commands << 'rm jetty-runtime/webapps/neo4jr-social.war'
59
+ commands << 'mv neo4jr-social.war jetty-runtime/webapps/neo4jr-social.war'
60
+ commands.each do |command|
61
+ STDERR.puts("Executing: #{command}")
62
+ `#{command}`
63
+ end
64
+ end
65
+
66
+ namespace :development do
67
+ task :start => :warify do
68
+ `bin/start-neo4jr-social`
69
+ end
70
+ end
data/TODO ADDED
@@ -0,0 +1,9 @@
1
+ * Figure out a better way to shebang for start-neo4jr-social
2
+ * Validate requests, check parameters, etc
3
+ * Figure out how we should handle the Neo4j node's classname
4
+ * Query Type: Amazon Recommendations
5
+ * Query Type: Most Popular
6
+ * Query Type: Primitive dynamic querying on all nodes
7
+ * Enable solr type parameters with lt gt eq etc
8
+ * Explore vendor-ize all ruby libs into WEB-INF
9
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env jruby-1.4.0
2
+
3
+ using_gems = false
4
+ begin
5
+ require 'fileutils'
6
+ require 'tempfile'
7
+ require 'tmpdir'
8
+ require 'optparse'
9
+ rescue LoadError => e
10
+ if using_gems
11
+ raise(e)
12
+ else
13
+ using_gems = true
14
+ require 'rubygems'
15
+ retry
16
+ end
17
+ end
18
+
19
+ working_directory = FileUtils.pwd
20
+ neo4j_social_install = File.expand_path(File.join(File.dirname(__FILE__), '..'))
21
+
22
+ port = '8988'
23
+ db_dir = nil
24
+ log_file = nil
25
+ log_level = 'OFF'
26
+ min_memory = '128m'
27
+ max_memory = '512m'
28
+
29
+ OptionParser.new do |opts|
30
+ opts.banner = "Usage: start-neo4jr-social [options]"
31
+
32
+ opts.on '-p', '--port=PORT', 'Port on which to run Neo4jr-social (default 8333)' do |p|
33
+ port = p
34
+ end
35
+
36
+ opts.on '-d', '--database=DIRECTORY', 'directory where the neo4jr database is located' do |d|
37
+ db_dir = File.expand_path(d)
38
+ end
39
+
40
+ opts.on '-l', '--log-level=LOG_LEVEL', 'Neo4jr-social logging level' do |l|
41
+ log_level = l
42
+ end
43
+
44
+ opts.on '--log-file=LOG_FILE', 'Path to Neo4jr-social log file' do |lf|
45
+ log_file = File.expand_path(lf)
46
+ end
47
+
48
+ opts.on '--max-memory=MEMORY', 'Specify the maximum size of the memory allocation pool' do |mm|
49
+ max_memory = mm
50
+ end
51
+
52
+ opts.on '--min-memory=MEMORY', 'Specify the initial size of the memory allocation pool' do |mm|
53
+ min_memory = mm
54
+ end
55
+ end.parse!
56
+
57
+ def logging_properties( log_file, log_level )
58
+ temp_file = Tempfile.new 'logging.properties'
59
+ temp_file << <<PROPERTIES
60
+ .level = #{log_level}
61
+ handlers = java.util.logging.FileHandler
62
+ java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
63
+ java.util.logging.FileHandler.pattern = #{log_file}
64
+ PROPERTIES
65
+ temp_file.flush
66
+ temp_file.close
67
+ temp_file.path
68
+ end
69
+
70
+ args = ['java']
71
+ args << "-Xms#{min_memory}"
72
+ args << "-Xmx#{max_memory}"
73
+ args << "-Djetty.port=#{port}" if port
74
+ args << "-Djetty.home=#{File.join(neo4j_social_install, 'jetty-runtime')}"
75
+ args << "-Dneo4jr.database=#{db_dir}" if db_dir
76
+ args << "-Djava.util.logging.config.file=#{logging_properties(log_file, log_level)}" if log_file and log_level != 'OFF'
77
+ args << '-jar' << File.join(neo4j_social_install, 'jetty-runtime', 'start.jar')
78
+ STDERR.puts(args * ' ')
79
+ Kernel.exec(args.join(' '))
data/config.ru ADDED
@@ -0,0 +1,3 @@
1
+ require 'lib/neo4jr-social'
2
+
3
+ run Neo4jr::Service
@@ -0,0 +1,33 @@
1
+ # neo4jr-social start -p8988
2
+
3
+ require 'rubygems'
4
+ require 'json'
5
+ require 'rest_client'
6
+
7
+ def create_person(name)
8
+ JSON.parse RestClient.post( "http://localhost:8988/neo4jr-social/nodes", :name => name )
9
+ end
10
+
11
+ def make_mutual_friends(node1, node2)
12
+ RestClient.post "http://localhost:8988/neo4jr-social/nodes/#{node1['node_id']}/relationships", :to => node2['node_id'], :type => 'friends'
13
+ RestClient.post "http://localhost:8988/neo4jr-social/nodes/#{node2['node_id']}/relationships", :to => node1['node_id'], :type => 'friends'
14
+ end
15
+
16
+ def suggestions_for(start_node)
17
+ JSON.parse RestClient.get("http://localhost:8988/neo4jr-social/nodes/#{start_node['node_id']}/recommendations?type=friends")
18
+ end
19
+
20
+ johnathan = create_person('Johnathan')
21
+ mark = create_person('Mark')
22
+ phill = create_person('Phill')
23
+ mary = create_person('Mary')
24
+ luke = create_person('Luke')
25
+
26
+ make_mutual_friends(johnathan, mark)
27
+ make_mutual_friends(mark, mary)
28
+ make_mutual_friends(mark, phill)
29
+ make_mutual_friends(phill, mary)
30
+ make_mutual_friends(phill, luke)
31
+
32
+ puts "Johnathan should become friends with #{suggestions_for(johnathan).map{|n| n['name']}.join(', ')}"
33
+ #=> Johnathan should become friends with Mary, Phill
@@ -0,0 +1,38 @@
1
+ # neo4jr-social start -p8988
2
+
3
+ require 'rubygems'
4
+ require 'json'
5
+ require 'rest_client'
6
+
7
+ def create_person(name)
8
+ response = RestClient.post "http://localhost:8988/neo4jr-social/nodes", :name => name
9
+ JSON.parse(response)
10
+ end
11
+
12
+ def make_mutual_friends(node1, node2)
13
+ RestClient.post "http://localhost:8988/neo4jr-social/nodes/#{node1['node_id']}/relationships", :to => node2['node_id'], :type => 'friends'
14
+ RestClient.post "http://localhost:8988/neo4jr-social/nodes/#{node2['node_id']}/relationships", :to => node1['node_id'], :type => 'friends'
15
+ end
16
+
17
+ def degrees_of_seperation(start_node, destination_node)
18
+ url = "http://localhost:8988/neo4jr-social/nodes/#{start_node['node_id']}/path?to=#{destination_node['node_id']}&type=friends&depth=3&direction=outgoing"
19
+ response = RestClient.get(url)
20
+ JSON.parse(response)
21
+ end
22
+
23
+ johnathan = create_person('Johnathan')
24
+ mark = create_person('Mark')
25
+ phill = create_person('Phill')
26
+ mary = create_person('Mary')
27
+
28
+ make_mutual_friends(johnathan, mark)
29
+ make_mutual_friends(mark, mary)
30
+ make_mutual_friends(mark, phill)
31
+ make_mutual_friends(phill, mary)
32
+
33
+ degrees_of_seperation(johnathan, mary).each do |path|
34
+ puts path.map{|node| node['name'] || node['type']}.join(' => ')
35
+ end
36
+
37
+ # Johnathan => friends => Mark => friends => Phill => friends => Mary
38
+ # Johnathan => friends => Mark => friends => Mary
@@ -0,0 +1,212 @@
1
+ <?xml version="1.0"?>
2
+ <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
3
+
4
+ <!-- =============================================================== -->
5
+ <!-- Configure the Jetty Server -->
6
+ <!-- -->
7
+ <!-- Documentation of this file format can be found at: -->
8
+ <!-- http://docs.codehaus.org/display/JETTY/jetty.xml -->
9
+ <!-- -->
10
+ <!-- =============================================================== -->
11
+
12
+
13
+ <Configure id="Server" class="org.mortbay.jetty.Server">
14
+
15
+ <!-- Increase the maximum POST size to 1 MB to be able to handle large shard requests -->
16
+ <Call class="java.lang.System" name="setProperty">
17
+ <Arg>org.mortbay.jetty.Request.maxFormContentSize</Arg>
18
+ <Arg>1000000</Arg>
19
+ </Call>
20
+
21
+ <!-- =========================================================== -->
22
+ <!-- Server Thread Pool -->
23
+ <!-- =========================================================== -->
24
+ <Set name="ThreadPool">
25
+ <!-- Default bounded blocking threadpool
26
+ -->
27
+ <New class="org.mortbay.thread.BoundedThreadPool">
28
+ <Set name="minThreads">10</Set>
29
+ <Set name="lowThreads">50</Set>
30
+ <Set name="maxThreads">10000</Set>
31
+ </New>
32
+
33
+ <!-- Optional Java 5 bounded threadpool with job queue
34
+ <New class="org.mortbay.thread.concurrent.ThreadPool">
35
+ <Arg type="int">0</Arg>
36
+ <Set name="corePoolSize">10</Set>
37
+ <Set name="maximumPoolSize">250</Set>
38
+ </New>
39
+ -->
40
+ </Set>
41
+
42
+
43
+
44
+ <!-- =========================================================== -->
45
+ <!-- Set connectors -->
46
+ <!-- =========================================================== -->
47
+ <!-- One of each type! -->
48
+ <!-- =========================================================== -->
49
+
50
+ <!-- Use this connector for many frequently idle connections
51
+ and for threadless continuations.
52
+ <Call name="addConnector">
53
+ <Arg>
54
+ <New class="org.mortbay.jetty.nio.SelectChannelConnector">
55
+ <Set name="port"><SystemProperty name="jetty.port" default="8983"/></Set>
56
+ <Set name="maxIdleTime">30000</Set>
57
+ <Set name="Acceptors">2</Set>
58
+ <Set name="confidentialPort">8443</Set>
59
+ </New>
60
+ </Arg>
61
+ </Call>
62
+ -->
63
+
64
+ <!-- Use this connector if NIO is not available. -->
65
+ <!-- This connector is currently being used for Solr because the
66
+ nio.SelectChannelConnector showed poor performance under WindowsXP
67
+ from a single client with non-persistent connections (35s vs ~3min)
68
+ to complete 10,000 requests)
69
+ -->
70
+ <Call name="addConnector">
71
+ <Arg>
72
+ <New class="org.mortbay.jetty.bio.SocketConnector">
73
+ <Set name="port"><SystemProperty name="jetty.port" default="8988"/></Set>
74
+ <Set name="maxIdleTime">50000</Set>
75
+ <Set name="lowResourceMaxIdleTime">1500</Set>
76
+ </New>
77
+ </Arg>
78
+ </Call>
79
+
80
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
81
+ <!-- To add a HTTPS SSL listener -->
82
+ <!-- see jetty-ssl.xml to add an ssl connector. use -->
83
+ <!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml -->
84
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
85
+
86
+ <!-- =========================================================== -->
87
+ <!-- Set up global session ID manager -->
88
+ <!-- =========================================================== -->
89
+ <!--
90
+ <Set name="sessionIdManager">
91
+ <New class="org.mortbay.jetty.servlet.HashSessionIdManager">
92
+ <Set name="workerName">node1</Set>
93
+ </New>
94
+ </Set>
95
+ -->
96
+
97
+ <!-- =========================================================== -->
98
+ <!-- Set handler Collection Structure -->
99
+ <!-- =========================================================== -->
100
+ <Set name="handler">
101
+ <New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection">
102
+ <Set name="handlers">
103
+ <Array type="org.mortbay.jetty.Handler">
104
+ <Item>
105
+ <New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/>
106
+ </Item>
107
+ <Item>
108
+ <New id="DefaultHandler" class="org.mortbay.jetty.handler.DefaultHandler"/>
109
+ </Item>
110
+ <Item>
111
+ <New id="RequestLog" class="org.mortbay.jetty.handler.RequestLogHandler"/>
112
+ </Item>
113
+ </Array>
114
+ </Set>
115
+ </New>
116
+ </Set>
117
+
118
+ <!-- =========================================================== -->
119
+ <!-- Configure the context deployer -->
120
+ <!-- A context deployer will deploy contexts described in -->
121
+ <!-- configuration files discovered in a directory. -->
122
+ <!-- The configuration directory can be scanned for hot -->
123
+ <!-- deployments at the configured scanInterval. -->
124
+ <!-- -->
125
+ <!-- This deployer is configured to deploy contexts configured -->
126
+ <!-- in the $JETTY_HOME/contexts directory -->
127
+ <!-- -->
128
+ <!-- =========================================================== -->
129
+ <Call name="addLifeCycle">
130
+ <Arg>
131
+ <New class="org.mortbay.jetty.deployer.ContextDeployer">
132
+ <Set name="contexts"><Ref id="Contexts"/></Set>
133
+ <Set name="configurationDir"><SystemProperty name="jetty.home" default="."/>/contexts</Set>
134
+ <Set name="scanInterval">1</Set>
135
+ </New>
136
+ </Arg>
137
+ </Call>
138
+
139
+ <!-- =========================================================== -->
140
+ <!-- Configure the webapp deployer. -->
141
+ <!-- A webapp deployer will deploy standard webapps discovered -->
142
+ <!-- in a directory at startup, without the need for additional -->
143
+ <!-- configuration files. It does not support hot deploy or -->
144
+ <!-- non standard contexts (see ContextDeployer above). -->
145
+ <!-- -->
146
+ <!-- This deployer is configured to deploy webapps from the -->
147
+ <!-- $JETTY_HOME/webapps directory -->
148
+ <!-- -->
149
+ <!-- Normally only one type of deployer need be used. -->
150
+ <!-- -->
151
+ <!-- =========================================================== -->
152
+ <Call name="addLifeCycle">
153
+ <Arg>
154
+ <New class="org.mortbay.jetty.deployer.WebAppDeployer">
155
+ <Set name="contexts"><Ref id="Contexts"/></Set>
156
+ <Set name="webAppDir"><SystemProperty name="jetty.home" default="."/>/webapps</Set>
157
+ <Set name="parentLoaderPriority">false</Set>
158
+ <Set name="extract">true</Set>
159
+ <Set name="allowDuplicates">false</Set>
160
+ <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
161
+ </New>
162
+ </Arg>
163
+ </Call>
164
+
165
+ <!-- =========================================================== -->
166
+ <!-- Configure Authentication Realms -->
167
+ <!-- Realms may be configured for the entire server here, or -->
168
+ <!-- they can be configured for a specific web app in a context -->
169
+ <!-- configuration (see $(jetty.home)/contexts/test.xml for an -->
170
+ <!-- example). -->
171
+ <!-- =========================================================== -->
172
+ <Set name="UserRealms">
173
+ <Array type="org.mortbay.jetty.security.UserRealm">
174
+ <!--
175
+ <Item>
176
+ <New class="org.mortbay.jetty.security.HashUserRealm">
177
+ <Set name="name">Test Realm</Set>
178
+ <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
179
+ </New>
180
+ </Item>
181
+ -->
182
+ </Array>
183
+ </Set>
184
+
185
+ <!-- =========================================================== -->
186
+ <!-- Configure Request Log -->
187
+ <!-- Request logs may be configured for the entire server here, -->
188
+ <!-- or they can be configured for a specific web app in a -->
189
+ <!-- contexts configuration (see $(jetty.home)/contexts/test.xml -->
190
+ <!-- for an example). -->
191
+ <!-- =========================================================== -->
192
+ <Ref id="RequestLog">
193
+ <Set name="requestLog">
194
+ <!-- New id="RequestLogImpl" class="org.mortbay.jetty.NCSARequestLog">
195
+ <Arg><SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Arg>
196
+ <Set name="retainDays">90</Set>
197
+ <Set name="append">true</Set>
198
+ <Set name="extended">false</Set>
199
+ <Set name="LogTimeZone">GMT</Set>
200
+ </New -->
201
+ </Set>
202
+ </Ref>
203
+
204
+ <!-- =========================================================== -->
205
+ <!-- extra options -->
206
+ <!-- =========================================================== -->
207
+ <Set name="stopAtShutdown">true</Set>
208
+ <!-- ensure/prevent Server: header being sent to browsers -->
209
+ <Set name="sendServerVersion">true</Set>
210
+
211
+ </Configure>
212
+