trinidad 1.4.4 → 1.4.5.B1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ module Trinidad
2
+ module Helpers
3
+
4
+ @@silence = nil # :nodoc
5
+ # Should we be silent - no warnings will be printed.
6
+ def self.silence?; @@silence; end
7
+ # Silence ! (... or I kill you)
8
+ def self.silence!; @@silence = true; end
9
+
10
+ # Print a warning (Kernel.warn).
11
+ def self.warn(msg)
12
+ super unless silence? # Kernel.warn
13
+ end
14
+
15
+ module_function
16
+
17
+ @@deprecated = {} # :nodoc
18
+
19
+ # Print a deprecated message (once - no matter how many times it's called).
20
+ def deprecate(msg, prefix = '[DEPRECATED] ')
21
+ return nil if @@deprecated[msg]
22
+ @@deprecated[msg] = true
23
+ Helpers.warn "#{prefix}#{msg}" # Kernel.warn
24
+ end
25
+
26
+ def camelize(string)
27
+ string = string.to_s.sub(/^[a-z\d]*/) { $&.capitalize }
28
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
29
+ string.gsub!('/', '::')
30
+ string
31
+ end
32
+
33
+ end
34
+ end
@@ -3,41 +3,42 @@ module Trinidad
3
3
  # Trinidad lifecycle listener (generic) base class.
4
4
  # Allows hooking into the container's lifecycle using the provided methods.
5
5
  class Base
6
-
6
+
7
7
  include Trinidad::Tomcat::LifecycleListener
8
8
 
9
+ EVENTS = Trinidad::Tomcat::Lifecycle # :nodoc:
10
+
9
11
  # The base implementation simply routes events to correspondig methods.
10
12
  #
11
13
  # http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/Lifecycle.html
12
14
  # http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/LifecycleListener.html
13
15
  def lifecycleEvent(event)
14
- events = Trinidad::Tomcat::Lifecycle
15
16
  case event.type
16
- when events::BEFORE_INIT_EVENT then
17
+ when EVENTS::BEFORE_INIT_EVENT then
17
18
  before_init(event)
18
- when events::AFTER_INIT_EVENT then
19
+ when EVENTS::AFTER_INIT_EVENT then
19
20
  after_init(event)
20
- when events::CONFIGURE_START_EVENT then
21
- configure_start(event)
22
- when events::CONFIGURE_STOP_EVENT then
23
- configure_stop(event)
24
- when events::BEFORE_START_EVENT then
21
+ when EVENTS::BEFORE_START_EVENT then
25
22
  before_start(event)
26
- when events::START_EVENT then
23
+ when EVENTS::CONFIGURE_START_EVENT then
24
+ configure_start(event)
25
+ when EVENTS::START_EVENT then
27
26
  start(event)
28
- when events::AFTER_START_EVENT then
27
+ when EVENTS::AFTER_START_EVENT then
29
28
  after_start(event)
30
- when events::BEFORE_STOP_EVENT then
29
+ when EVENTS::BEFORE_STOP_EVENT then
31
30
  before_stop(event)
32
- when events::STOP_EVENT then
31
+ when EVENTS::STOP_EVENT then
33
32
  stop(event)
34
- when events::AFTER_STOP_EVENT then
33
+ when EVENTS::CONFIGURE_STOP_EVENT then
34
+ configure_stop(event)
35
+ when EVENTS::AFTER_STOP_EVENT then
35
36
  after_stop(event)
36
- when events::BEFORE_DESTROY_EVENT then
37
+ when EVENTS::BEFORE_DESTROY_EVENT then
37
38
  before_destroy(event)
38
- when events::AFTER_DESTROY_EVENT then
39
+ when EVENTS::AFTER_DESTROY_EVENT then
39
40
  after_destroy(event)
40
- when events::PERIODIC_EVENT then
41
+ when EVENTS::PERIODIC_EVENT then
41
42
  periodic(event)
42
43
  else
43
44
  raise "unsupported event.type = #{event.type}"
@@ -48,16 +49,15 @@ module Trinidad
48
49
 
49
50
  def before_init(event); end
50
51
  def after_init(event); end
51
-
52
- def configure_start(event); end
53
- def configure_stop(event); end
54
52
 
55
53
  def before_start(event); end
54
+ def configure_start(event); end
56
55
  def start(event); end
57
56
  def after_start(event); end
58
57
 
59
58
  def before_stop(event); end
60
59
  def stop(event); end
60
+ def configure_stop(event); end
61
61
  def after_stop(event); end
62
62
 
63
63
  def before_destroy(event); end
@@ -2,8 +2,13 @@ require 'trinidad/lifecycle/base'
2
2
 
3
3
  module Trinidad
4
4
  module Lifecycle
5
- # A host lifecycle listener - monitors deployed web apps.
6
- class Host < Base
5
+ # Host listener - monitors deployed applications
6
+ # (re-invented HostConfig with Ruby/Rack semantics).
7
+ class Host # TODO < Tomcat::HostConfig !
8
+
9
+ include Trinidad::Tomcat::LifecycleListener
10
+
11
+ EVENTS = Trinidad::Tomcat::Lifecycle # :nodoc:
7
12
 
8
13
  attr_reader :server, :app_holders
9
14
  # @deprecated (<= 1.3.5)
@@ -21,21 +26,40 @@ module Trinidad
21
26
  end
22
27
  @server, @app_holders = server, app_holders
23
28
  end
24
-
25
- # @see Trinidad::Lifecycle::Base#before_start
29
+
30
+ def lifecycleEvent(event) # :nodoc:
31
+ case event.type
32
+ when EVENTS::BEFORE_START_EVENT then
33
+ before_start(event)
34
+ when EVENTS::START_EVENT then
35
+ start(event)
36
+ when EVENTS::STOP_EVENT then
37
+ stop(event)
38
+ when EVENTS::PERIODIC_EVENT then
39
+ periodic(event)
40
+ end
41
+ end
42
+
26
43
  def before_start(event)
27
44
  init_monitors
28
45
  end
29
46
 
30
- # @see Trinidad::Lifecycle::Base#periodic
47
+ def start(event); end # :nodoc:
48
+
31
49
  def periodic(event)
32
- check_monitors
50
+ check_changes event.lifecycle
33
51
  end
34
52
 
35
- def tomcat; @server.tomcat; end # for backwards compatibility
53
+ def stop(event); end # :nodoc:
54
+
55
+ def tomcat; @server.tomcat; end # :nodoc: for backwards compatibility
36
56
 
37
57
  protected
38
58
 
59
+ def check_changes(host)
60
+ check_monitors
61
+ end
62
+
39
63
  def init_monitors
40
64
  app_holders.each do |app_holder|
41
65
  monitor = app_holder.monitor
@@ -80,8 +104,9 @@ module Trinidad
80
104
  strategy = (app_holder.web_app.reload_strategy || :default).to_sym
81
105
  strategy = RELOAD_STRATEGIES[ strategy ]
82
106
  strategy = strategy ? self.class.const_get(strategy) : RestartReload
83
- strategy.instance_method(:initialize).arity != 0 ?
84
- strategy.new(server).reload!(app_holder) : strategy.new.reload!(app_holder)
107
+ new_args = []
108
+ new_args << server if strategy.instance_method(:initialize).arity != 0
109
+ strategy.new(*new_args).reload!(app_holder)
85
110
  end
86
111
 
87
112
  end
@@ -16,19 +16,32 @@ module Trinidad
16
16
 
17
17
  web_app.reset! # force a new class loader + re-read state (from config)
18
18
  no_host = org.apache.catalina.Host.impl {} # do not add to parent yet
19
- new_context = @server.add_web_app(web_app, no_host)
20
- new_context.add_lifecycle_listener(Takeover.new(old_context))
19
+ new_context = @server.add_web_app(web_app, no_host, false)
21
20
  # Tomcat requires us to have unique names for its containers :
22
21
  new_context.name = "#{old_context.name}-#{java.lang.System.currentTimeMillis}"
23
-
22
+ new_context.add_lifecycle_listener(takeover = Takeover.new(old_context))
24
23
  app_holder.context = new_context
25
24
 
26
25
  Thread.new do
27
26
  begin
28
27
  logger.debug "Starting a new Context for [#{new_context.path}]"
29
28
  old_context.parent.add_child new_context # NOTE: likely starts!
30
- new_context.start unless new_context.state_name =~ /START/i
31
- logger.info "Context with name [#{old_context.name}] has completed rolling"
29
+
30
+ new_context.start unless new_context.state_name =~ /START|STOP|FAILED/i
31
+
32
+ if new_context.state_name =~ /STOP|FAILED/i
33
+ logger.error("Context with name [#{old_context.name}] failed rolling")
34
+ takeover.failed!(new_context)
35
+ else
36
+ logger.info "Context with name [#{old_context.name}] has completed rolling"
37
+ end
38
+ rescue => error
39
+ e = org.jruby.exceptions.RaiseException.new(error)
40
+ logger.error("Context with name [#{old_context.name}] failed rolling", e)
41
+ takeover.failed!(new_context)
42
+ rescue java.lang.Exception => e
43
+ logger.error("Context with name [#{old_context.name}] failed rolling", e)
44
+ takeover.failed!(new_context)
32
45
  ensure
33
46
  app_holder.unlock
34
47
  end
@@ -39,9 +52,9 @@ module Trinidad
39
52
  def self.logger # log into the same location as context.reload does :
40
53
  Trinidad::Logging::LogFactory.getLog('org.apache.catalina.core.StandardContext')
41
54
  end
42
-
55
+
43
56
  class Takeover < Trinidad::Lifecycle::Base # :nodoc
44
-
57
+
45
58
  def initialize(context)
46
59
  @old_context = context
47
60
  end
@@ -53,12 +66,21 @@ module Trinidad
53
66
  logger.debug "Stoping the old Context for [#{@old_context.path}]"
54
67
 
55
68
  @old_context.stop
69
+ @old_context.work_dir = nil # make sure it's not deleted
56
70
  @old_context.destroy
57
71
  # NOTE: name might not be changed once added to a parent
58
- new_context.name = @old_context.name
72
+ #new_context.name = @old_context.name
59
73
  super
60
74
  end
61
75
 
76
+ def failed!(new_context)
77
+ # NOTE: this will also likely destroy() the child - new context :
78
+ @old_context.parent.remove_child new_context
79
+ logger.info "Failed to start new Context for [#{@old_context.path}] " +
80
+ "(check application logs) keeping the old one running ..."
81
+ new_context.remove_lifecycle_listener(self)
82
+ end
83
+
62
84
  private
63
85
 
64
86
  def logger
@@ -66,7 +88,7 @@ module Trinidad
66
88
  end
67
89
 
68
90
  end
69
-
91
+
70
92
  end
71
93
  end
72
94
  end
@@ -31,7 +31,7 @@ module Trinidad
31
31
  def configure_deployment_descriptor(context)
32
32
  descriptor = web_app.deployment_descriptor
33
33
  if descriptor && File.exist?(descriptor)
34
- listeners = context.findLifecycleListeners
34
+ listeners = context.find_lifecycle_listeners
35
35
  context_config = listeners && listeners.find do |listener|
36
36
  listener.is_a?(Trinidad::Tomcat::ContextConfig)
37
37
  end
@@ -12,6 +12,12 @@ module Trinidad
12
12
  @web_app = web_app
13
13
  end
14
14
 
15
+ def before_init(event)
16
+ #context = event.lifecycle
17
+ #context.name = context.path if context.name
18
+ super
19
+ end
20
+
15
21
  # @see Trinidad::Lifecycle::Base#before_start
16
22
  def before_start(event)
17
23
  super
@@ -30,7 +36,12 @@ module Trinidad
30
36
  protected
31
37
 
32
38
  def adjust_context(context)
33
- context.name = web_app.context_name if web_app.context_name
39
+ context_name = web_app.context_name
40
+ # on (rolling) reloads the name may have been set already :
41
+ if context_name && ! (context.name || '').index(context_name)
42
+ context.name = context_name
43
+ end
44
+
34
45
  context.doc_base = web_app.doc_base if web_app.doc_base
35
46
  context.work_dir = web_app.work_dir if web_app.work_dir
36
47
  context.aliases = web_app.aliases if web_app.aliases
@@ -47,19 +58,15 @@ module Trinidad
47
58
 
48
59
  def configure_default_servlet(context)
49
60
  configure_builtin_servlet(context,
50
- web_app.default_servlet,
51
- Trinidad::WebApp::DEFAULT_SERVLET_NAME
61
+ web_app.default_servlet, Trinidad::WebApp::DEFAULT_SERVLET_NAME
52
62
  )
53
63
  end
54
64
 
55
65
  def configure_jsp_servlet(context)
56
66
  wrapper = configure_builtin_servlet(context,
57
- web_app.jsp_servlet,
58
- Trinidad::WebApp::JSP_SERVLET_NAME
67
+ web_app.jsp_servlet, Trinidad::WebApp::JSP_SERVLET_NAME
59
68
  )
60
- if wrapper == false # jsp servlet removed
61
- context.process_tlds = false
62
- end
69
+ context.process_tlds = false if wrapper == false # jsp servlet removed
63
70
  wrapper
64
71
  end
65
72
 
@@ -7,45 +7,45 @@ module Trinidad
7
7
  class War < Base
8
8
  include Shared
9
9
 
10
- def before_start(event)
11
- expand_war_app(event.lifecycle)
12
- super # Shared#before_start
13
- end
14
-
15
- def after_start(event)
10
+ def before_init(event)
11
+ # NOTE: esp. important for .war applications that the name matches the path
12
+ # to work-around ProxyDirContext constructor's `contextPath = contextName;`
13
+ # @see {#adjust_context} also need to restore possible context name change!
14
+ context = event.lifecycle
15
+ context.name = context.path if context.name
16
16
  super
17
- remove_war_app(event.lifecycle)
18
17
  end
19
18
 
20
19
  def configure(context)
21
- super # TODO assuming warbler .war !
20
+ super # Shared#configure
22
21
  configure_class_loader(context)
23
22
  end
24
-
23
+
25
24
  protected
26
25
 
26
+ def adjust_context(context)
27
+ name = context.name
28
+ super
29
+ ensure # @see {#before_init}
30
+ context.name = name
31
+ # NOTE: mimics HostConfig#deploWAR and should be removed
32
+ # once Lifecycle::Host inherits func from HostConfig ...
33
+ # context_name = Trinidad::Tomcat::ContextName.new(name)
34
+ # context.setName context_name.getName()
35
+ # context.setPath context_name.getPath()
36
+ # context.setWebappVersion context_name.getVersion()
37
+ # context.setDocBase context_name.getBaseName() + '.war'
38
+ end
39
+
27
40
  def configure_class_loader(context)
28
- loader = Trinidad::Tomcat::WebappLoader.new(web_app.class_loader)
41
+ class_loader = web_app.class_loader || JRuby.runtime.jruby_class_loader
42
+ loader = Trinidad::Tomcat::WebappLoader.new(class_loader)
29
43
  loader.container = context
30
44
  context.loader = loader
31
45
  end
32
46
 
33
- private
34
-
35
- def expand_war_app(context)
36
- unless File.exist?(context.doc_base)
37
- host = context.parent
38
- war_file = java.io.File.new(web_app.root_dir)
39
- war = java.net.URL.new("jar:" + war_file.toURI.toURL.to_s + "!/")
40
- path_name = File.basename(context.doc_base)
41
-
42
- Trinidad::Tomcat::ExpandWar.expand(host, war, path_name)
43
- end
44
- end
45
-
46
- def remove_war_app(context)
47
- require 'fileutils'
48
- FileUtils.rm_rf web_app.root_dir.gsub(/\.war$/, '')
47
+ def remove_defaults(context = nil)
48
+ # NOTE: do not remove defaults (welcome files)
49
49
  end
50
50
 
51
51
  end
@@ -12,17 +12,13 @@ module Trinidad
12
12
  # Configure the "global" Trinidad logging.
13
13
  def self.configure(log_level = nil)
14
14
  return false if @@configured
15
+ @@configured = true
15
16
 
16
17
  root_logger = JUL::Logger.getLogger('')
17
18
  level = parse_log_level(log_level, :INFO)
18
19
 
19
20
  out_handler = new_console_handler JRuby.runtime.out
20
21
  out_handler.formatter = console_formatter
21
-
22
- err_handler = new_console_handler JRuby.runtime.err
23
- err_handler.formatter = console_formatter
24
- err_handler.level = level.intValue > JUL::Level::WARNING.intValue ?
25
- level : JUL::Level::WARNING # only >= WARNING on STDERR
26
22
 
27
23
  root_logger.synchronized do
28
24
  root_logger.handlers.to_a.each do |handler|
@@ -30,24 +26,35 @@ module Trinidad
30
26
  end
31
27
 
32
28
  root_logger.add_handler(out_handler)
33
- root_logger.add_handler(err_handler)
34
- root_logger.level = level
29
+ if JRuby.runtime.out != Java::JavaLang::System.out ||
30
+ JRuby.runtime.err != Java::JavaLang::System.err
31
+ # NOTE: only add err handler if customized STDOUT or STDERR :
32
+ err_handler = new_console_handler JRuby.runtime.err
33
+ err_handler.formatter = console_formatter
34
+ err_handler.level = level.intValue > JUL::Level::WARNING.intValue ?
35
+ level : JUL::Level::WARNING # only >= WARNING on STDERR
36
+
37
+ root_logger.add_handler(err_handler)
38
+ end
39
+ set_log_level(root_logger, level)
35
40
  end
36
- adjust_tomcat_loggers
41
+ silence_tomcat_loggers
37
42
 
38
- @@configured = true
39
43
  root_logger
40
44
  end
41
45
 
42
46
  # Force logging (re-)configuration.
43
47
  # @see #configure
44
48
  def self.configure!(log_level = nil)
45
- @@configured = false
46
- configure(log_level)
49
+ ( @@configured = false ) || configure(log_level)
50
+ end
51
+
52
+ def self.configure_web_app!(web_app, context)
53
+ configure_web_app!(web_app, context, true)
47
54
  end
48
55
 
49
56
  # Configure logging for a web application.
50
- def self.configure_web_app(web_app, context)
57
+ def self.configure_web_app(web_app, context, reset = nil)
51
58
  param_name, param_value = 'jruby.rack.logging', 'JUL'
52
59
  # 1. delegate (jruby-rack) servlet log to JUL
53
60
  if set_value = web_app_context_param(web_app, context, param_name)
@@ -62,12 +69,15 @@ module Trinidad
62
69
  # org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/foo]
63
70
  context.add_parameter(param_name, logger_name = context.send(:logName))
64
71
  end
65
- configure # make sure 'global' logging if configured
72
+ configure # make sure 'global' logging is configured
66
73
 
67
74
  logger = JUL::Logger.getLogger(logger_name) # exclusive for web app
68
- # avoid duplicate calls - do not configure our FileHandler twice :
69
- return false if logger.handlers.find { |h| h.is_a?(FileHandler) }
75
+ logger.handlers.each { |h| logger.remove_handler(h); h.close } if reset
76
+ # avoid duplicate calls - do not configure (e.g. FileHandler) twice :
77
+ return false unless logger.handlers.empty?
78
+
70
79
  logging = web_app.logging
80
+
71
81
  logger.level = parse_log_level(logging[:level], nil)
72
82
  # delegate to root (console) output only in development mode :
73
83
  logger.use_parent_handlers = logging[:use_parent_handlers]
@@ -112,16 +122,26 @@ module Trinidad
112
122
  JUL::Level.parse(log_level) if log_level
113
123
  end
114
124
 
115
- def self.adjust_tomcat_loggers
125
+ def self.set_log_level(logger, level)
126
+ logger.level = level; LogFactory.getLog(logger.name)
127
+ end
128
+
129
+ def self.silence_tomcat_loggers
116
130
  # org.apache.coyote.http11.Http11Protocol INFO: Initializing ProtocolHandler ["http-bio-3000"]
117
131
  # org.apache.catalina.core.StandardService INFO: Starting service Tomcat
118
132
  # org.apache.catalina.core.StandardEngine INFO: Starting Servlet Engine: Apache Tomcat/7.0.27
119
133
  # org.apache.catalina.startup.ContextConfig INFO: No global web.xml found
120
134
  # org.apache.coyote.http11.Http11Protocol INFO: Starting ProtocolHandler ["http-bio-3000"]
121
- logger = JUL::Logger.get_logger('org.apache.catalina.core.StandardService')
122
- logger.level = JUL::Level::WARNING if logger
123
- logger = JUL::Logger.get_logger('org.apache.catalina.startup.ContextConfig')
124
- logger.level = JUL::Level::WARNING if logger
135
+ level = JUL::Level::WARNING
136
+ logger_names = [
137
+ 'org.apache.catalina.core.StandardService',
138
+ 'org.apache.catalina.core.StandardEngine',
139
+ 'org.apache.catalina.startup.ContextConfig',
140
+ ]
141
+ for name in logger_names
142
+ logger = JUL::Logger.getLogger(name)
143
+ set_log_level(logger, level) if logger
144
+ end
125
145
  end
126
146
 
127
147
  def self.web_app_context_param(web_app, context, name)
@@ -146,78 +166,82 @@ module Trinidad
146
166
  handler
147
167
  end
148
168
 
149
- # we'd achieve logging to a production.log file while rotating it (daily)
150
- class FileHandler < Java::OrgApacheJuli::FileHandler # :nodoc
151
-
152
- field_reader :directory, :prefix, :suffix
153
- field_accessor :rotatable, :bufferSize => :buffer_size
154
-
155
- # JULI::FileHandler internals :
156
- field_accessor :date => :_date # current date string e.g. 2012-06-26
157
-
158
- def initialize(directory, prefix, suffix)
159
- super(directory, prefix, suffix)
160
- self._date = nil # to openWriter on first #publish(record)
161
- end
162
-
163
- def openWriter
164
- # NOTE: following code is heavily based on super's internals !
165
- synchronized do
166
- # we're normally in the lock here (from #publish)
167
- # thus we do not perform any more synchronization
168
- prev_rotatable = self.rotatable
169
- begin
170
- self.rotatable = false
171
- # thus current file name will be always {prefix}{suffix} :
172
- # due super's `prefix + (rotatable ? _date : "") + suffix`
173
- super
174
- ensure
175
- self.rotatable = prev_rotatable
176
- end
169
+ if ( Java::JavaClass.for_name('rb.trinidad.logging.FileHandler') rescue nil )
170
+ FileHandler = Java::RbTrinidadLogging::FileHandler # recent trinidad_jars
171
+ else
172
+ # we'd achieve logging to a production.log file while rotating it (daily)
173
+ class FileHandler < Java::OrgApacheJuli::FileHandler # :nodoc
174
+
175
+ field_reader :directory, :prefix, :suffix
176
+ field_accessor :rotatable, :bufferSize => :buffer_size
177
+
178
+ # JULI::FileHandler internals :
179
+ field_accessor :date => :_date # current date string e.g. 2012-06-26
180
+
181
+ def initialize(directory, prefix, suffix)
182
+ super(directory, prefix, suffix)
183
+ self._date = nil # to openWriter on first #publish(record)
177
184
  end
178
- end
179
185
 
180
- def close
181
- @_close = true
182
- super
183
- @_close = nil
184
- end
185
-
186
- def closeWriter
187
- date = _date
188
- super # sets `date = null`
189
- # the additional trick here is to rotate the closed file
190
- synchronized do
191
- # we're normally in the lock here (from #publish)
192
- # thus we do not perform any more synchronization
193
- dir = java.io.File.new(directory).getAbsoluteFile
194
- log = java.io.File.new(dir, prefix + "" + suffix)
195
- if log.exists
196
- if ! date || date.empty?
197
- date = log.lastModified
198
- # we abuse Timestamp to get a date formatted !
199
- # just like super does internally (just in case)
200
- date = java.sql.Timestamp.new(date).toString[0, 10]
201
- end
202
- today = java.lang.System.currentTimeMillis
203
- today = java.sql.Timestamp.new(today).toString[0, 10]
204
- return if date == today # no need to rotate just yet
205
- to_file = java.io.File.new(dir, prefix + date + suffix)
206
- if to_file.exists
207
- file = java.io.RandomAccessFile.new(to_file, 'rw')
208
- file.seek(file.length)
209
- log_channel = java.io.FileInputStream.new(log).getChannel
210
- log_channel.transferTo(0, log_channel.size, file.getChannel)
211
- file.close
212
- log_channel.close
213
- log.delete
214
- else
215
- log.renameTo(to_file)
186
+ def openWriter
187
+ # NOTE: following code is heavily based on super's internals !
188
+ synchronized do
189
+ # we're normally in the lock here (from #publish)
190
+ # thus we do not perform any more synchronization
191
+ prev_rotatable = self.rotatable
192
+ begin
193
+ self.rotatable = false
194
+ # thus current file name will be always {prefix}{suffix} :
195
+ # due super's `prefix + (rotatable ? _date : "") + suffix`
196
+ super
197
+ ensure
198
+ self.rotatable = prev_rotatable
216
199
  end
217
200
  end
218
- end if rotatable && ! @_close
201
+ end
202
+
203
+ def close
204
+ @_close = true
205
+ super
206
+ @_close = nil
207
+ end
208
+
209
+ def closeWriter
210
+ date = _date
211
+ super # sets `date = null`
212
+ # the additional trick here is to rotate the closed file
213
+ synchronized do
214
+ # we're normally in the lock here (from #publish)
215
+ # thus we do not perform any more synchronization
216
+ dir = java.io.File.new(directory).getAbsoluteFile
217
+ log = java.io.File.new(dir, prefix + "" + suffix)
218
+ if log.exists
219
+ if ! date || date.empty?
220
+ date = log.lastModified
221
+ # we abuse Timestamp to get a date formatted !
222
+ # just like super does internally (just in case)
223
+ date = java.sql.Timestamp.new(date).toString[0, 10]
224
+ end
225
+ today = java.lang.System.currentTimeMillis
226
+ today = java.sql.Timestamp.new(today).toString[0, 10]
227
+ return if date == today # no need to rotate just yet
228
+ to_file = java.io.File.new(dir, prefix + date + suffix)
229
+ if to_file.exists
230
+ file = java.io.RandomAccessFile.new(to_file, 'rw')
231
+ file.seek(file.length)
232
+ log_channel = java.io.FileInputStream.new(log).getChannel
233
+ log_channel.transferTo(0, log_channel.size, file.getChannel)
234
+ file.close
235
+ log_channel.close
236
+ log.delete
237
+ else
238
+ log.renameTo(to_file)
239
+ end
240
+ end
241
+ end if rotatable && ! @_close
242
+ end
243
+
219
244
  end
220
-
221
245
  end
222
246
 
223
247
  # We're truly missing a #formatThrown exception helper method.
@@ -265,47 +289,52 @@ module Trinidad
265
289
 
266
290
  end
267
291
 
268
- # A formatter that formats application file logs (e.g. production.log).
269
- class DefaultFormatter < JUL::Formatter # :nodoc
292
+ if ( Java::JavaClass.for_name('rb.trinidad.logging.DefaultFormatter') rescue nil )
293
+ DefaultFormatter = Java::RbTrinidadLogging::DefaultFormatter # recent trinidad_jars
294
+ else
295
+ # A formatter that formats application file logs (e.g. production.log).
296
+ class DefaultFormatter < JUL::Formatter # :nodoc
270
297
 
271
- # Allows customizing the date format + the time zone to be used.
272
- def initialize(format = nil, time_zone = nil)
273
- super()
274
- @format = format ?
275
- Java::JavaText::SimpleDateFormat.new(format) :
276
- Java::JavaText::SimpleDateFormat.new
277
- case time_zone
278
- when Java::JavaUtil::Calendar then
279
- @format.calendar = time_zone
280
- when Java::JavaUtil::TimeZone then
281
- @format.time_zone = time_zone
282
- when String then
283
- time_zone = Java::JavaUtil::TimeZone.getTimeZone(time_zone)
284
- @format.time_zone = time_zone
285
- when Numeric then
286
- time_zones = Java::JavaUtil::TimeZone.getAvailableIDs(time_zone)
287
- if time_zones.length > 0
288
- time_zone = Java::JavaUtil::TimeZone.getTimeZone(time_zones[0])
298
+ # Allows customizing the date format + the time zone to be used.
299
+ def initialize(format = nil, time_zone = nil)
300
+ super()
301
+ @format = format ?
302
+ Java::JavaText::SimpleDateFormat.new(format) :
303
+ Java::JavaText::SimpleDateFormat.new
304
+ case time_zone
305
+ when Java::JavaUtil::Calendar then
306
+ @format.calendar = time_zone
307
+ when Java::JavaUtil::TimeZone then
289
308
  @format.time_zone = time_zone
290
- end
291
- end if time_zone
292
- end
309
+ when String then
310
+ time_zone = Java::JavaUtil::TimeZone.getTimeZone(time_zone)
311
+ @format.time_zone = time_zone
312
+ when Numeric then
313
+ time_zones = Java::JavaUtil::TimeZone.getAvailableIDs(time_zone)
314
+ if time_zones.length > 0
315
+ time_zone = Java::JavaUtil::TimeZone.getTimeZone(time_zones[0])
316
+ @format.time_zone = time_zone
317
+ end
318
+ end if time_zone
319
+ end
293
320
 
294
- JDate = Java::JavaUtil::Date
321
+ JDate = Java::JavaUtil::Date
295
322
 
296
- def format(record)
297
- timestamp = @format.synchronized do
298
- @format.format JDate.new(record.millis)
323
+ def format(record)
324
+ timestamp = @format.synchronized do
325
+ @format.format JDate.new(record.millis)
326
+ end
327
+ level = record.level.name
328
+ message = formatMessage(record)
329
+
330
+ out = "#{timestamp} #{level}: #{message}"
331
+ out << formatThrown(record).to_s
332
+ (lns = "\n") == out[-1, 1] ? out : out << lns
299
333
  end
300
- level = record.level.name
301
- message = formatMessage(record)
302
334
 
303
- out = "#{timestamp} #{level}: #{message}"
304
- out << formatThrown(record).to_s
305
- (lns = "\n") == out[-1, 1] ? out : out << lns
306
335
  end
307
-
308
336
  end
337
+
309
338
  end
310
339
  LogFormatter = Logging::DefaultFormatter # backwards compatibility
311
340
  end