sunspot 0.10.9 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/History.txt +30 -0
  2. data/README.rdoc +59 -29
  3. data/Rakefile +2 -0
  4. data/TODO +9 -19
  5. data/VERSION.yml +2 -3
  6. data/bin/sunspot-installer +19 -0
  7. data/bin/sunspot-solr +28 -53
  8. data/installer/config/schema.yml +71 -0
  9. data/lib/sunspot/configuration.rb +0 -10
  10. data/lib/sunspot/dsl/field_query.rb +123 -7
  11. data/lib/sunspot/dsl/fields.rb +17 -4
  12. data/lib/sunspot/dsl/query.rb +11 -3
  13. data/lib/sunspot/dsl/scope.rb +6 -2
  14. data/lib/sunspot/field.rb +4 -7
  15. data/lib/sunspot/field_factory.rb +8 -5
  16. data/lib/sunspot/indexer.rb +22 -20
  17. data/lib/sunspot/installer/library_installer.rb +45 -0
  18. data/lib/sunspot/installer/schema_builder.rb +219 -0
  19. data/lib/sunspot/installer/solrconfig_updater.rb +90 -0
  20. data/lib/sunspot/installer/task_helper.rb +18 -0
  21. data/lib/sunspot/installer.rb +31 -0
  22. data/lib/sunspot/query/abstract_field_facet.rb +5 -1
  23. data/lib/sunspot/query/connective.rb +3 -1
  24. data/lib/sunspot/query/field_facet.rb +33 -1
  25. data/lib/sunspot/query/filter.rb +38 -0
  26. data/lib/sunspot/query/local.rb +10 -11
  27. data/lib/sunspot/query/query.rb +5 -12
  28. data/lib/sunspot/query/restriction.rb +2 -1
  29. data/lib/sunspot/query/scope.rb +1 -1
  30. data/lib/sunspot/query.rb +3 -3
  31. data/lib/sunspot/schema.rb +5 -1
  32. data/lib/sunspot/search/field_facet.rb +59 -15
  33. data/lib/sunspot/search/hit.rb +21 -10
  34. data/lib/sunspot/search/query_facet.rb +2 -2
  35. data/lib/sunspot/search.rb +86 -33
  36. data/lib/sunspot/server.rb +148 -0
  37. data/lib/sunspot/session.rb +39 -51
  38. data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
  39. data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
  40. data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
  41. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
  42. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +206 -0
  43. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +30 -0
  44. data/lib/sunspot/session_proxy.rb +71 -0
  45. data/lib/sunspot/setup.rb +24 -10
  46. data/lib/sunspot/type.rb +163 -101
  47. data/lib/sunspot/util.rb +44 -2
  48. data/lib/sunspot/version.rb +3 -0
  49. data/lib/sunspot.rb +50 -17
  50. data/solr/etc/jetty.xml +4 -2
  51. data/solr/solr/conf/admin-extra.html +31 -0
  52. data/solr/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  53. data/solr/solr/conf/schema.xml +212 -50
  54. data/solr/solr/conf/scripts.conf +24 -0
  55. data/solr/solr/conf/solrconfig.xml +473 -266
  56. data/solr/solr/conf/spellings.txt +2 -0
  57. data/solr/solr/conf/stopwords.txt +1 -0
  58. data/solr/solr/lib/lucene-spatial-2.9.1.jar +0 -0
  59. data/solr/solr/lib/solr-spatial-light-0.0.3.jar +0 -0
  60. data/solr/webapps/solr.war +0 -0
  61. data/spec/api/binding_spec.rb +38 -0
  62. data/spec/api/indexer/attributes_spec.rb +37 -4
  63. data/spec/api/indexer/dynamic_fields_spec.rb +10 -1
  64. data/spec/api/indexer/removal_spec.rb +8 -1
  65. data/spec/api/indexer_spec.rb +10 -0
  66. data/spec/api/query/dsl_spec.rb +6 -0
  67. data/spec/api/query/dynamic_fields_spec.rb +9 -9
  68. data/spec/api/query/facet_local_params_spec.rb +103 -0
  69. data/spec/api/query/local_spec.rb +13 -37
  70. data/spec/api/query/ordering_pagination_spec.rb +0 -6
  71. data/spec/api/search/dynamic_fields_spec.rb +3 -3
  72. data/spec/api/search/faceting_spec.rb +113 -10
  73. data/spec/api/search/hits_spec.rb +49 -0
  74. data/spec/api/search/results_spec.rb +8 -1
  75. data/spec/api/server_spec.rb +85 -0
  76. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
  77. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
  78. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
  79. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
  80. data/spec/api/session_proxy/spec_helper.rb +9 -0
  81. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +33 -0
  82. data/spec/ext.rb +11 -0
  83. data/spec/helpers/search_helper.rb +6 -8
  84. data/spec/integration/faceting_spec.rb +46 -4
  85. data/spec/integration/indexing_spec.rb +27 -1
  86. data/spec/integration/local_search_spec.rb +25 -7
  87. data/spec/integration/scoped_search_spec.rb +48 -36
  88. data/spec/mocks/comment.rb +7 -5
  89. data/spec/mocks/connection.rb +14 -13
  90. data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
  91. data/spec/mocks/mock_record.rb +7 -3
  92. data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
  93. data/spec/mocks/photo.rb +4 -3
  94. data/spec/mocks/post.rb +1 -1
  95. data/spec/spec_helper.rb +2 -1
  96. data/tasks/gemspec.rake +26 -36
  97. data/tasks/rdoc.rake +9 -4
  98. metadata +203 -203
  99. data/bin/sunspot-configure-solr +0 -40
  100. data/solr/solr/lib/geoapi-nogenerics-2.1-M2.jar +0 -0
  101. data/solr/solr/lib/gt2-referencing-2.3.1.jar +0 -0
  102. data/solr/solr/lib/jsr108-0.01.jar +0 -0
  103. data/solr/solr/lib/locallucene.jar +0 -0
  104. data/solr/solr/lib/localsolr.jar +0 -0
  105. data/templates/schema.xml.erb +0 -36
data/lib/sunspot/type.rb CHANGED
@@ -17,6 +17,19 @@ module Sunspot
17
17
  # Ruby type.
18
18
  #
19
19
  module Type
20
+ class AbstractType #:nodoc:
21
+ class <<self
22
+ def instance
23
+ @instance ||= new
24
+ end
25
+ private :new
26
+ end
27
+
28
+ def accepts_dynamic?
29
+ true
30
+ end
31
+ end
32
+
20
33
  #
21
34
  # Text is a special type that stores data for fulltext search. Unlike other
22
35
  # types, Text fields are tokenized and are made available to the keyword
@@ -24,76 +37,91 @@ module Sunspot
24
37
  # restrictions. Similarly, text fields are the only fields that are made
25
38
  # available to keyword search.
26
39
  #
27
- module TextType
28
- class <<self
29
- def indexed_name(name) #:nodoc:
40
+ class TextType < AbstractType
41
+ def indexed_name(name) #:nodoc:
30
42
  "#{name}_text"
31
- end
43
+ end
32
44
 
33
- def to_indexed(value) #:nodoc:
34
- value.to_s if value
35
- end
45
+ def to_indexed(value) #:nodoc:
46
+ value.to_s if value
47
+ end
36
48
 
37
- def cast(text)
38
- text
39
- end
49
+ def cast(text)
50
+ text
51
+ end
52
+
53
+ def accepts_dynamic?
54
+ false
40
55
  end
41
56
  end
42
57
 
43
58
  #
44
59
  # The String type represents string data.
45
60
  #
46
- module StringType
47
- class <<self
48
- def indexed_name(name) #:nodoc:
61
+ class StringType < AbstractType
62
+ def indexed_name(name) #:nodoc:
49
63
  "#{name}_s"
50
- end
64
+ end
51
65
 
52
- def to_indexed(value) #:nodoc:
53
- value.to_s if value
54
- end
66
+ def to_indexed(value) #:nodoc:
67
+ value.to_s if value
68
+ end
55
69
 
56
- def cast(string) #:nodoc:
57
- string
58
- end
70
+ def cast(string) #:nodoc:
71
+ string
59
72
  end
60
73
  end
61
74
 
62
75
  #
63
76
  # The Integer type represents integers.
64
77
  #
65
- module IntegerType
66
- class <<self
67
- def indexed_name(name) #:nodoc:
78
+ class IntegerType < AbstractType
79
+ def indexed_name(name) #:nodoc:
68
80
  "#{name}_i"
69
- end
81
+ end
70
82
 
71
- def to_indexed(value) #:nodoc:
72
- value.to_i.to_s if value
73
- end
83
+ def to_indexed(value) #:nodoc:
84
+ value.to_i.to_s if value
85
+ end
74
86
 
75
- def cast(string) #:nodoc:
76
- string.to_i
77
- end
87
+ def cast(string) #:nodoc:
88
+ string.to_i
89
+ end
90
+ end
91
+
92
+ #
93
+ # The Long type indexes Ruby Fixnum and Bignum numbers into Java Longs
94
+ #
95
+ class LongType < IntegerType
96
+ def indexed_name(name) #:nodoc:
97
+ "#{name}_l"
78
98
  end
79
99
  end
80
100
 
81
101
  #
82
102
  # The Float type represents floating-point numbers.
83
103
  #
84
- module FloatType
85
- class <<self
86
- def indexed_name(name) #:nodoc:
104
+ class FloatType < AbstractType
105
+ def indexed_name(name) #:nodoc:
87
106
  "#{name}_f"
88
- end
107
+ end
89
108
 
90
- def to_indexed(value) #:nodoc:
91
- value.to_f.to_s if value
92
- end
109
+ def to_indexed(value) #:nodoc:
110
+ value.to_f.to_s if value
111
+ end
93
112
 
94
- def cast(string) #:nodoc:
95
- string.to_f
96
- end
113
+ def cast(string) #:nodoc:
114
+ string.to_f
115
+ end
116
+ end
117
+
118
+ #
119
+ # The Double type indexes Ruby Floats (which are in fact doubles) into Java
120
+ # Double fields
121
+ #
122
+ class DoubleType < FloatType
123
+ def indexed_name(name)
124
+ "#{name}_e"
97
125
  end
98
126
  end
99
127
 
@@ -101,27 +129,40 @@ module Sunspot
101
129
  # The time type represents times. Note that times are always converted to
102
130
  # UTC before indexing, and facets of Time fields always return times in UTC.
103
131
  #
104
- module TimeType
132
+ class TimeType < AbstractType
133
+ XMLSCHEMA = "%Y-%m-%dT%H:%M:%SZ"
105
134
 
106
- class <<self
107
- def indexed_name(name) #:nodoc:
135
+ def indexed_name(name) #:nodoc:
108
136
  "#{name}_d"
109
- end
137
+ end
110
138
 
111
- def to_indexed(value) #:nodoc:
112
- if value
113
- time =
114
- if value.respond_to?(:utc)
115
- value
116
- else
117
- Time.parse(value.to_s)
118
- end
119
- time.utc.xmlschema
120
- end
139
+ def to_indexed(value) #:nodoc:
140
+ if value
141
+ value_to_utc_time(value).strftime(XMLSCHEMA)
121
142
  end
143
+ end
122
144
 
123
- def cast(string) #:nodoc:
145
+ def cast(string) #:nodoc:
146
+ begin
124
147
  Time.xmlschema(string)
148
+ rescue ArgumentError
149
+ DateTime.strptime(string, XMLSCHEMA)
150
+ end
151
+ end
152
+
153
+ private
154
+
155
+ def value_to_utc_time(value)
156
+ if value.respond_to?(:utc)
157
+ value.utc
158
+ elsif value.respond_to?(:new_offset)
159
+ value.new_offset
160
+ else
161
+ begin
162
+ Time.parse(value.to_s).utc
163
+ rescue ArgumentError
164
+ DateTime.parse(value.to_s).new_offset
165
+ end
125
166
  end
126
167
  end
127
168
  end
@@ -132,72 +173,93 @@ module Sunspot
132
173
  # Solr's DateField type (which is actually date/time), midnight UTC of the
133
174
  # indexed date.
134
175
  #
135
- module DateType
136
- class <<self
137
- def indexed_name(name) #:nodoc:
138
- "#{name}_d"
176
+ class DateType < TimeType
177
+ def to_indexed(value) #:nodoc:
178
+ if value
179
+ time =
180
+ if %w(year mon mday).all? { |method| value.respond_to?(method) }
181
+ Time.utc(value.year, value.mon, value.mday)
182
+ else
183
+ date = Date.parse(value.to_s)
184
+ Time.utc(date.year, date.mon, date.mday)
185
+ end
186
+ super(time)
139
187
  end
188
+ end
140
189
 
141
- def to_indexed(value) #:nodoc:
142
- if value
143
- time =
144
- if %w(year mon mday).all? { |method| value.respond_to?(method) }
145
- Time.utc(value.year, value.mon, value.mday)
146
- else
147
- date = Date.parse(value.to_s)
148
- Time.utc(date.year, date.mon, date.mday)
149
- end
150
- time.utc.xmlschema
151
- end
152
- end
190
+ def cast(string) #:nodoc:
191
+ time = super
192
+ Date.civil(time.year, time.mon, time.mday)
193
+ end
194
+ end
153
195
 
154
- def cast(string) #:nodoc:
155
- time = Time.xmlschema(string)
156
- Date.civil(time.year, time.mon, time.mday)
157
- end
196
+ #
197
+ # Store integers in a TrieField, which makes range queries much faster.
198
+ #
199
+ class TrieIntegerType < IntegerType
200
+ def indexed_name(name)
201
+ "#{super}t"
202
+ end
203
+ end
204
+
205
+ #
206
+ # Store floats in a TrieField, which makes range queries much faster.
207
+ #
208
+ class TrieFloatType < FloatType
209
+ def indexed_name(name)
210
+ "#{super}t"
158
211
  end
159
212
  end
160
213
 
214
+ #
215
+ # Index times using a TrieField. Internally, trie times are indexed as
216
+ # Unix timestamps in a trie integer field, as TrieField does not support
217
+ # datetime types natively. This distinction should have no effect from the
218
+ # standpoint of the library's API.
219
+ #
220
+ class TrieTimeType < TimeType
221
+ def indexed_name(name)
222
+ "#{super}t"
223
+ end
224
+ end
225
+
226
+
161
227
  #
162
228
  # The boolean type represents true/false values. Note that +nil+ will not be
163
229
  # indexed at all; only +false+ will be indexed with a false value.
164
230
  #
165
- module BooleanType
166
- class <<self
167
- def indexed_name(name) #:nodoc:
231
+ class BooleanType < AbstractType
232
+ def indexed_name(name) #:nodoc:
168
233
  "#{name}_b"
169
- end
234
+ end
170
235
 
171
- def to_indexed(value) #:nodoc:
172
- unless value.nil?
173
- value ? 'true' : 'false'
174
- end
236
+ def to_indexed(value) #:nodoc:
237
+ unless value.nil?
238
+ value ? 'true' : 'false'
175
239
  end
240
+ end
176
241
 
177
- def cast(string) #:nodoc:
178
- case string
179
- when 'true'
180
- true
181
- when 'false'
182
- false
183
- end
242
+ def cast(string) #:nodoc:
243
+ case string
244
+ when 'true'
245
+ true
246
+ when 'false'
247
+ false
184
248
  end
185
249
  end
186
250
  end
187
251
 
188
- module ClassType
189
- class <<self
190
- def indexed_name(name) #:nodoc:
191
- 'class_name'
192
- end
252
+ class ClassType < AbstractType
253
+ def indexed_name(name) #:nodoc:
254
+ 'class_name'
255
+ end
193
256
 
194
- def to_indexed(value) #:nodoc:
195
- value.name
196
- end
257
+ def to_indexed(value) #:nodoc:
258
+ value.name
259
+ end
197
260
 
198
- def cast(string) #:nodoc:
199
- Sunspot::Util.full_const_get(string)
200
- end
261
+ def cast(string) #:nodoc:
262
+ Sunspot::Util.full_const_get(string)
201
263
  end
202
264
  end
203
265
  end
data/lib/sunspot/util.rb CHANGED
@@ -83,7 +83,7 @@ module Sunspot
83
83
  if block.arity > 0
84
84
  block.call(object)
85
85
  else
86
- object.instance_eval(&block)
86
+ ContextBoundDelegate.instance_eval_with_context(object, &block)
87
87
  end
88
88
  end
89
89
 
@@ -189,8 +189,10 @@ module Sunspot
189
189
  def lat
190
190
  if @coords.respond_to?(:[])
191
191
  @coords[0]
192
- else
192
+ elsif @coords.respond_to?(:lat)
193
193
  @coords.lat
194
+ else
195
+ @coords.latitude
194
196
  end.to_f
195
197
  end
196
198
 
@@ -203,8 +205,48 @@ module Sunspot
203
205
  @coords.lon
204
206
  elsif @coords.respond_to?(:long)
205
207
  @coords.long
208
+ elsif @coords.respond_to?(:longitude)
209
+ @coords.longitude
206
210
  end.to_f
207
211
  end
208
212
  end
213
+
214
+ class ContextBoundDelegate
215
+ class <<self
216
+ def instance_eval_with_context(receiver, &block)
217
+ calling_context = eval('self', block.binding)
218
+ if parent_calling_context = calling_context.instance_eval{@__calling_context__}
219
+ calling_context = parent_calling_context
220
+ end
221
+ new(receiver, calling_context).instance_eval(&block)
222
+ end
223
+ private :new
224
+ end
225
+
226
+ BASIC_METHODS = Set[:==, :equal?, :"!", :"!=", :instance_eval,
227
+ :object_id, :__send__, :__id__]
228
+
229
+ instance_methods.each do |method|
230
+ unless BASIC_METHODS.include?(method.to_sym)
231
+ undef_method(method)
232
+ end
233
+ end
234
+
235
+ def initialize(receiver, calling_context)
236
+ @__receiver__, @__calling_context__ = receiver, calling_context
237
+ end
238
+
239
+ def method_missing(method, *args, &block)
240
+ begin
241
+ @__receiver__.send(method.to_sym, *args, &block)
242
+ rescue ::NoMethodError => e
243
+ begin
244
+ @__calling_context__.send(method.to_sym, *args, &block)
245
+ rescue ::NoMethodError
246
+ raise(e)
247
+ end
248
+ end
249
+ end
250
+ end
209
251
  end
210
252
  end
@@ -0,0 +1,3 @@
1
+ module Sunspot
2
+ VERSION = '1.0.0'
3
+ end
data/lib/sunspot.rb CHANGED
@@ -2,6 +2,7 @@ require 'set'
2
2
  require 'time'
3
3
  require 'date'
4
4
  require 'enumerator'
5
+ require 'cgi'
5
6
  begin
6
7
  require 'rsolr'
7
8
  rescue LoadError
@@ -12,8 +13,8 @@ end
12
13
  require File.join(File.dirname(__FILE__), 'light_config')
13
14
 
14
15
  %w(util adapters configuration setup composite_setup text_field_setup field
15
- field_factory data_extractor indexer query search session type
16
- dsl).each do |filename|
16
+ field_factory data_extractor indexer query search session session_proxy
17
+ type dsl).each do |filename|
17
18
  require File.join(File.dirname(__FILE__), 'sunspot', filename)
18
19
  end
19
20
 
@@ -33,12 +34,15 @@ end
33
34
  # method) is _not_ session-specific, but rather global.
34
35
  #
35
36
  module Sunspot
36
- UnrecognizedFieldError = Class.new(Exception)
37
- UnrecognizedRestrictionError = Class.new(Exception)
38
- NoAdapterError = Class.new(Exception)
39
- NoSetupError = Class.new(Exception)
40
- IllegalSearchError = Class.new(Exception)
37
+ UnrecognizedFieldError = Class.new(StandardError)
38
+ UnrecognizedRestrictionError = Class.new(StandardError)
39
+ NoAdapterError = Class.new(StandardError)
40
+ NoSetupError = Class.new(StandardError)
41
+ IllegalSearchError = Class.new(StandardError)
42
+ NotImplementedError = Class.new(StandardError)
41
43
 
44
+ autoload :Server, File.join(File.dirname(__FILE__), 'sunspot', 'server')
45
+ autoload :Installer, File.join(File.dirname(__FILE__), 'sunspot', 'installer')
42
46
 
43
47
  class <<self
44
48
  #
@@ -204,9 +208,30 @@ module Sunspot
204
208
 
205
209
  #
206
210
  # Create a new Search instance, but do not execute it immediately. Generally
207
- # you will want to use the #search method to execute searches using the
208
- # DSL; however, if you are building searches dynamically (using the Builder
209
- # pattern, for instance), it may be easier to access the Query API directly.
211
+ # you will want to use the #search method to build and execute searches in
212
+ # one step, but if you are building searches piecemeal you may call
213
+ # #new_search and then call #build one or more times to add components to
214
+ # the query.
215
+ #
216
+ # ==== Example
217
+ #
218
+ # search = Sunspot.new_search do
219
+ # with(:blog_id, 1)
220
+ # end
221
+ # search.build do
222
+ # keywords('some keywords')
223
+ # end
224
+ # search.build do
225
+ # order_by(:published_at, :desc)
226
+ # end
227
+ # search.execute
228
+ #
229
+ # # This is equivalent to:
230
+ # Sunspot.search do
231
+ # with(:blog_id, 1)
232
+ # keywords('some keywords')
233
+ # order_by(:published_at, :desc)
234
+ # end
210
235
  #
211
236
  # ==== Parameters
212
237
  #
@@ -220,8 +245,8 @@ module Sunspot
220
245
  # Search object, not yet executed. Query parameters can be added manually;
221
246
  # then #execute! should be called.
222
247
  #
223
- def new_search(*types)
224
- session.new_search(*types)
248
+ def new_search(*types, &block)
249
+ session.new_search(*types, &block)
225
250
  end
226
251
 
227
252
 
@@ -303,18 +328,28 @@ module Sunspot
303
328
  # references to objects that do not exist, which will cause errors when
304
329
  # those objects are matched in search results.
305
330
  #
331
+ # If a block is passed, it is evaluated as a search scope; in this way,
332
+ # documents can be removed by an arbitrary query. In this case, the
333
+ # arguments to the method should be the classes to run the query on.
334
+ #
306
335
  # ==== Parameters
307
336
  #
308
337
  # objects...<Object>::
309
338
  # Objects to remove from the index (may pass an array or varargs)
310
339
  #
311
- # ==== Example
340
+ # ==== Example (remove a document)
312
341
  #
313
342
  # post.destroy
314
343
  # Sunspot.remove(post)
315
344
  #
316
- def remove(*objects)
317
- session.remove(*objects)
345
+ # ==== Example (remove by query)
346
+ #
347
+ # Sunspot.remove(Post) do
348
+ # with(:created_at).less_than(Time.now - 14.days)
349
+ # end
350
+ #
351
+ def remove(*objects, &block)
352
+ session.remove(*objects, &block)
318
353
  end
319
354
 
320
355
  #
@@ -472,8 +507,6 @@ module Sunspot
472
507
  @session = Session.new(config)
473
508
  end
474
509
 
475
- private
476
-
477
510
  #
478
511
  # Get the singleton session, creating it if none yet exists.
479
512
  #
data/solr/etc/jetty.xml CHANGED
@@ -189,17 +189,19 @@
189
189
  <!-- contexts configuration (see $(jetty.home)/contexts/test.xml -->
190
190
  <!-- for an example). -->
191
191
  <!-- =========================================================== -->
192
+ <!--
192
193
  <Ref id="RequestLog">
193
194
  <Set name="requestLog">
194
- <!-- New id="RequestLogImpl" class="org.mortbay.jetty.NCSARequestLog">
195
+ <New id="RequestLogImpl" class="org.mortbay.jetty.NCSARequestLog">
195
196
  <Arg><SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Arg>
196
197
  <Set name="retainDays">90</Set>
197
198
  <Set name="append">true</Set>
198
199
  <Set name="extended">false</Set>
199
200
  <Set name="LogTimeZone">GMT</Set>
200
- </New -->
201
+ </New>
201
202
  </Set>
202
203
  </Ref>
204
+ -->
203
205
 
204
206
  <!-- =========================================================== -->
205
207
  <!-- extra options -->
@@ -0,0 +1,31 @@
1
+ <!--
2
+ Licensed to the Apache Software Foundation (ASF) under one or more
3
+ contributor license agreements. See the NOTICE file distributed with
4
+ this work for additional information regarding copyright ownership.
5
+ The ASF licenses this file to You under the Apache License, Version 2.0
6
+ (the "License"); you may not use this file except in compliance with
7
+ the License. You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ -->
17
+
18
+ <!-- The content of this page will be statically included into the top
19
+ of the admin page. Uncomment this as an example to see there the content
20
+ will show up.
21
+
22
+ <hr>
23
+ <i>This line will appear before the first table</i>
24
+ <tr>
25
+ <td colspan="2">
26
+ This row will be appended to the end of the first table
27
+ </td>
28
+ </tr>
29
+ <hr>
30
+
31
+ -->