如何在 Tomcat 中的 Rails 初始化期间创建全局命名空间常量?

发布于 2024-12-20 11:18:52 字数 2187 浏览 2 评论 0原文

首先是一些背景知识:我有一个 Rails 2.2.2 应用程序,其中包含各种混乱的依赖项和自定义项,使我暂时无法升级到 2.2.2 以上。目前的计划是将此应用程序迁移到 JRuby (1.6.5),将其部署为 Tomcat 中的 war(6.0.23 - 尚未与此特定版本 FWIW 绑定),并使用 warbler (1.3.2) 将其打包。

我希望避免应用程序的 JRuby 分支与普通应用程序有很大差异,因为我不知道需要多长时间来梳理并修复由运行时环境差异引起的所有问题。因此,我希望能够继续干净、轻松地合并普通应用程序中正在进行的工作。

应用程序中的许多自定义行为可以使用 environments/*.rb 文件中设置的全局命名空间常量进行配置。但这些值可以通过使用 yaml 配置文件或设置 shell 环境变量来覆盖;这主要是为了开发过程中的灵活性,不同的开发人员有时需要自定义各种设置。到目前为止,该系统运行良好,使我们的 environments/development.rb 文件相对稳定且整洁,同时在我们进行黑客攻击时仍然为我们提供了对自定义的大量控制。

我想在迁移到 JRuby 时保留这个定制系统。到目前为止,我正在使用自定义的 config/web.xml.erb 将相关环境变量和设置从 yaml 文件转换为 片段,这使得它们在初始化期间通过 java:comp/env JNDI 上下文可用。在更受限制的环境(例如登台或生产)中,可以通过在容器的 context.xml 文件中包含相应的 设置来锁定其中许多设置override 属性设置为 false

到目前为止,一切都很好。但现在我正在努力在初始化期间将从 JNDI 上下文检索到的值转换为全局命名空间常量。以下是相关位的摘录:

config/environments/developer.rb:

...
envset "FOO", "baz"
FOO="fail" unless defined? FOO
printf "FOO is now '%s'\n", FOO
 ...

lib/config_helper.rb:

1  include Java
2  import javax.naming.InitialContext
3  import javax.naming.NameNotFoundException
4  
5  ctx = InitialContext.new
6  
7  def envset(value_name, default_value)
8      value = nil
9      begin
10         value = ctx.lookup("java:comp/env/#{value_name}")
11     rescue NameNotFoundException => e
12         value = default_value
13     end
14     printf "setting %s to '%s'\n", value_name, value
15     eval("%Q[ #{value_name} = '#{value}' ]")
16 end

web.xml:

...
<env-entry>
    <env-entry-name>FOO</env-entry-name>
    <env-entry-value>bar</env-entry-value>
    <env-entry-type>java.lang.String</env-entry-type>
</env-entry>
...

catalina.out:

setting FOO to 'bar'
FOO is now 'fail'

当然,我期望最后一行是“FOO 现在是'bar'” 。 lib/config_helper.rb 的第 14 行似乎是出了问题的地方。类似的代码在 vanilla ruby​​ 中运行良好,但在 Tomcat 初始化期间不起作用。

那么,在 Tomcat 中 Rails 初始化期间,如何从 JNDI 环境条目中创建全局命名空间常量呢?

First some background: I've got a Rails 2.2.2 app with all kinds of janky dependencies and customizations that keep me from upgrading past 2.2.2 for the moment. Current plan is to migrate this app to JRuby (1.6.5), deploying it as a war in Tomcat (6.0.23—not yet tied to this particular version FWIW), using warbler (1.3.2) to package it up.

I want to keep the JRuby branch of the app from diverging substantially from the vanilla app since I don't know how long it's going to take to tease out and fix all of the issues caused by discrepancies in the runtime environments. So I want to be able to continue to cleanly and easily merge in ongoing work from the vanilla app.

A number of customized behaviors in the app can be configured with globally namespaced CONSTANTs set in the environments/*.rb files. But these values can be overridden by using a yaml configuration file or setting a shell environment variable; this is primarily for flexibility during development, where different devs sometimes need to customize various settings. This system has worked well so far, leaving our environments/development.rb file relatively stable and uncluttered while still giving us a great deal of control over customization as we're hacking.

I would like to preserve this system of customization in the move to JRuby. So far, I'm using a customized config/web.xml.erb that converts relevant environment variables and settings from the yaml file into <env-entry> fragments, which makes them available during initialization via the java:comp/env JNDI context. In more restricted environments (like staging or production), many of these settings can be locked down by including corresponding <Environment> settings in the container's context.xml file with the override attribute set to false.

So far, so good. But now I am struggling to turn the values retrieved from the JNDI context into global namespace CONSTANTs during initialization. Here are excerpts of the relevant bits:

config/environments/developer.rb:

...
envset "FOO", "baz"
FOO="fail" unless defined? FOO
printf "FOO is now '%s'\n", FOO
 ...

lib/config_helper.rb:

1  include Java
2  import javax.naming.InitialContext
3  import javax.naming.NameNotFoundException
4  
5  ctx = InitialContext.new
6  
7  def envset(value_name, default_value)
8      value = nil
9      begin
10         value = ctx.lookup("java:comp/env/#{value_name}")
11     rescue NameNotFoundException => e
12         value = default_value
13     end
14     printf "setting %s to '%s'\n", value_name, value
15     eval("%Q[ #{value_name} = '#{value}' ]")
16 end

web.xml:

...
<env-entry>
    <env-entry-name>FOO</env-entry-name>
    <env-entry-value>bar</env-entry-value>
    <env-entry-type>java.lang.String</env-entry-type>
</env-entry>
...

catalina.out:

setting FOO to 'bar'
FOO is now 'fail'

Where I am expecting this last line to be "FOO is now 'bar'", of course. Line 14 of lib/config_helper.rb seems to be where things are going wrong. Similar code has worked fine in vanilla ruby, but it doesn't work here during initialization in Tomcat.

So, how can I create globally namespaced CONSTANTs out of JNDI environment entries during Rails initialization in Tomcat?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

神经暖 2024-12-27 11:18:52

一个好的经验法则是总是有比eval()更好的答案。用以下行替换第 15 行可以正确地在全局命名空间中创建常量:

Object.const_set(value_name, value)

我仍然不确定原始命名空间是在哪个命名空间中创建常量,但 Object 似乎是“全局”命名空间。

A good rule of thumb is that there is always a better answer than eval(). Replacing line 15 with the following line correctly creates constants in the global namespace:

Object.const_set(value_name, value)

I'm still not sure what namespace the original was creating constants in, but Object appears to be the "global" one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文