blog20100901

2013/08/20 - プログラミング言語 Perl にまつわる etc. - Perl monger
参考 : perldoc, perldoc.jp, search.cpan.org, perldoc.perl.org ...
「 初めての Perl 第 6 版 」(オライリー・ジャパン発行 ISBN978-4-87311-567-2) 」
「 続・初めての Perl 改訂版 」(オライリー・ジャパン発行 ISBN4-87311-305-9) 」
「 Effective Perl 第 2 版 」(翔泳社発行 ISBN978-4-7981-3981-4) 」 ... etc,.

Perl Perl_7 mod_perl 翻訳 Web Server

Perl mp2 翻訳 Apache:: Perl モジュールを 1.0 から 2.0 に移植する (d192)

目次 - Perl Index


Theme



Perl について、復習を兼ねて断片的な情報を掲載して行く連載その d192 回。

今回は、「 mod_perl Home / The mod_perl Web Site / Documentation / mod_perl 2.0 Documentation / User's guide / Part IV: Porting / Proting Apache:: Perl Modules from mod_perl 1.0 to 2.0 」を翻訳して確認します。

正確な内容は 原文 を確認してください。誤解や誤訳がある場合はご指摘ください。





説明 : Description


This document describes the various options for porting a mod_perl 1.0 Apache module so that it runs on a Apache 2.0 / mod_perl 2.0 server. It's also helpful to those who start developing mod_perl 2.0 handlers.

Developers who need to port modules using XS code, should also read about porting Apache:: XS modules.

There is also: Porting CPAN modules to mod_perl 2.0 Status.

このドキュメントは mod_perl 1.0 Apache モジュールを Apache 2.0 / mod_perl 2.0 サー上で実行するためのさまざまなオプションを説明しています。それは mod_perl 2.0 ハンドラの開発を始めるためにも役立ちます。

XS コードを使ったモジュールの移植が必要な開発者は, porting Apache:: XS modules も読むとよいでしょう。

これもあります: Porting CPAN modules to mod_perl 2.0 Status


イントロダクション : Introduction


In the vast majority of cases, a perl Apache module that runs under mod_perl 1.0 will not run under mod_perl 2.0 without at least some degree of modification.

基本的には, mod_perl 1.0 のもとで走る perl Apache モジュールは少なくともある程度の修正なくして mod_perl 2.0 のもとでは走りません
Even a very simple module that does not in itself need any changes will at least need the mod_perl 2.0 Apache modules loaded, because in mod_perl 2.0 basic functionality, such as access to the request object and returning an HTTP status, is not found where, or implemented how it used to be in mod_perl 1.0.

それ自身はなんの変更も必要としないとてもシンプルなモジュールでさえ, mod_perl 2.0 ではリクエストオブジェクトへのアクセスや HTTP ステータスのリターンのような基本機能が, どこにあるかわからない, または mod_perl 1.0 で使われていた方法で実装されていないため, 少なくとも mod_perl 2.0 Apache モジュールのロードが必要です。
Most real-life modules will in fact need to deal with the following changes:

現実にあるほとんどのモジュールは次の変更に対して実際に対処する必要があります:

  • methods that have moved to a different (new) package

    別の (新しい) パッケージに移動したメソッド

  • methods that must be called differently (due to changed prototypes)

    別の方法でコールされなければならないメソッド (プロトタイプが変更されたことによる)

  • methods that have ceased to exist (functionality provided in some other way)

    存在しなくなったメソッド (他の方法で提供される機能)


Do not be alarmed! One way to deal with all of these issues is to load the Apache2::compat compatibility layer bundled with mod_perl 2.0. This magic spell will make almost any 1.0 module run under 2.0 without further changes. It is by no means the solution for every case, however, so please read carefully the following discussion of this and other options.

心配しないでください ! これらすべての問題に対処するための方法の 1 つは mod_perl 2.0 にバンドルされた互換レイヤ Apache2::compat をロードすることです。この魔法はほとんどの 1.0 モジュールをあまり変更することなく 2.0 のもとで走るようにします。けれども, これはすべてのケースでの解決策ではありませんので, 以下のおよび他のオプションのディスカッションを注意深く読んでください。
There are three basic options for porting. Let's take a quick look at each one and then discuss each in more detail.

移植のためのオプションが 3 つあります。それぞれを簡単にみてからそれぞれの詳細を論じます。


  1. Run the module on 2.0 under Apache2::compat with no further changes

    余り変更せずに Apache2::compat のもとの 2.0 でモジュールを実行する
    As we have said mod_perl 2.0 ships with a module, Apache2::compat, that provides a complete drop-in compatibility layer for 1.0 modules. Apache2::compat does the following:

    私たちが述べたように mod_perl 2.0 にはモジュールが付属しています, それは Apache2::comat で, 1.0 モジュールのために完全なドロップインの互換レイヤを提供します。Apache2::compat は次のことを行います:

    • Loads all the mod_perl 2.0 Apache2:: modules

      すべての mod_perl 2.0 Apache2:: モジュールをロードする

    • Adjusts method calls where the prototype has changed

      プロトタイプが変更された場所のメソッドコールを調整する

    • Provides Perl implementation for methods that no longer exist in 2.0

      2.0 でもう存在しないメソッドのための Perl 実装を提供する


    The drawback to using Apache2::compat is the performance hit, which can be significant.

    Apache2::compat を使う欠点はパフォーマンスが低下することで, これは重要になります。
    Authors of CPAN and other publicly distributed modules should not use Apache2::compat since this forces its use in environments where the administrator may have chosen to optimize memory use by making all code run natively under 2.0.

    管理者が 2.0 ですべてのコードをネイティブに実行するようにしてメモリの利用の最適化を選択したかもしれない環境での使用をも強制するので CPAN と他で公に配布されているモジュールの作者は Apache2::compat を使わない方がよいです。


  2. Modify the module to run only under 2.0

    2.0 のもとでのみ走るようにモジュールを修正する
    If you are not interested in providing backwards compatibility with mod_perl 1.0, or if you plan to leave your 1.0 module in place and develop a new version compatible with 2.0, you will need to make changes to your code. How significant or widespread the changes are depends largely of course on your existing code.

    もしあなたが mod_perl 1.0 との後方互換性を提供することに興味がない場合, またはあなたの 1.0 モジュールそのままにして 2.0 互換の新しいバージョンの開発をあなたが計画しているなら, あなたはあなたのコードを変更する必要があります。その変更がどれだけ重要で広範囲になるかはもちろん既存のあなたのコードに大きく依存します。
    Several sections of this document provide detailed information on how to rewrite your code for mod_perl 2.0 Several tools are provided to help you, and it should be a relatively painless task and one that you only have to do once.

    このドキュメントのいくつかのセクションは mod_perl 2.0 のためにあなたのコードをどのようにリライトするかについて詳しい情報を提供します。あなたをヘルプするいくつかのツールが提供されていて, それは比較的簡単なタスクであなたはそれを 1 度だけ行えばよいはずです。


  3. Modify the module so that it runs under both 1.0 and 2.0

    モジュールを 1.0 と 2.0 の両方のもとで走るように修正する
    You need to do this if you want to keep the same version number for your module, or if you distribute your module on CPAN and want to maintain and release just one codebase.

    あなたがあなたのモジュールで同じバージョン番号を維持したい場合, またはあなたがあなたのモジュールを CPAN で配布していて 1 つのコードベースでメンテとリリースをしたい場合にあなたはこれを必要とします。
    This is a relatively simple enhancement of option (2) above. The module tests to see which version of mod_perl is in use and then executes the appropriate method call.

    これは上記のオプション (2) の比較的シンプルな強化版です。モジュールは使われている mod_perl のバージョンを見るためにテストししてから適切なメソッドコールを実行します。


The following sections provide more detailed information and instructions for each of these three porting strategies.

次のセクションはこれら 3 つの移植戦略それぞれのより詳細な情報と手順を提供します。


Apache2::porting を使う : Using Apache2::porting


META: to be written. this is a new package which makes chunks of this doc simpler. for now see the Apache2::porting manpage.

META: 書くこと。これはこのドキュメントのチャンクをより簡単にする新しいパッケージ。いまは Apache2::porting man ページを参照。


Apache2::compat レイヤを使う : Using the Apache2::compat Layer


The Apache2::compat module tries to hide the changes in API prototypes between version 1.0 and 2.0 of mod_perl, and implements "virtual methods" for the methods and functions that actually no longer exist.

Apache2::compat モジュールはバージョン 1.0 と 2.0 の mod_perl の間の API プロトタイプの変更を隠すようにトライして, 実際にはもう存在しないメソッドとファンクションのための "バーチャルメソッド" を実装します。
Apache2::compat is extremely easy to use. Either add at the very beginning of startup.pl:

Apache2::compat は極めて簡単に使えます。startup.pl の最初の方に追加するか:

use Apache2::compat;

or add to httpd.conf:

または httpd.conf に追加するかのいずれかです:

PerlModule Apache2::compat

That's all there is to it. Now you can run your 1.0 module unchanged.

これがすべてです。これであなたの 1.0 モジュールは変更することなく走ります。
Remember, however, that using Apache2::compat will make your module run slower. It can create a larger memory footprint than you need and it implements functionality in pure Perl that is provided in much faster XS in mod_perl 1.0 as well as in 2.0. This module was really designed to assist in the transition from 1.0 to 2.0. Generally you will be better off if you port your code to use the mod_perl 2.0 API.

しかし, 覚えておいてください, Apache2::compat の利用はあなたのモジュールの実行をより遅くします。
それはあなたが必要とする以上の大きなメモリフットプリントを作成しますし mod_perl 1.0 でも 2.0 でもはるかに高速な XS で提供されている機能をピュア Perl で実装します。
このモジュールは 1.0 から 2.0 への移行をアシストするためにリアルに設計されました。通常はあなたがあなたのコードを mod_perl 2.0 API を使うように移植するとあなたはベターになります
It's also especially important to repeat that CPAN module developers are requested not to use this module in their code, since this takes the control over performance away from users.

これはユーザからパフォーマンスのコントロールを取り去ってしまうので, 繰り返し CPAN モジュール開発者がそのコードでこのモジュールを使わないようにとリクエストされていることも特に重要です。


mod_perl 2.0 で実行するために Perl モジュールを移植する : Porting a Perl Module to Run under mod_perl 2.0


Note: API changes are listed in the mod_perl 1.0 backward compatibility document.

The following sections will guide you through the steps of porting your modules to mod_perl 2.0.

Note: API の変更は mod_perl 1.0 backward compatibility ドキュメントにリストされています。

次のセクションはあなたのモジュールの mod_perl 2.0 への移植のステップを通してあなたをガイドします。


ロードが必要な mod_perl 2.0 モジュールを ModPerl::MethodLookup を使って発見する : Using ModPerl::MethodLookup to Discover Which mod_perl 2.0 Modules Need to Be Loaded


It would certainly be nice to have our mod_perl 1.0 code run on the mod_perl 2.0 server unmodified. So first of all, try your luck and test the code.

私たちの mod_perl 1.0 コードを修正せずに mod_perl 2.0 サーバで実行してみることはたしかにナイスです。ですからまずはじめに, あなたの運試しでコードをテストします。
It's almost certain that your code won't work when you try, however, because mod_perl 2.0 splits functionality across many more modules than version 1.0 did, and you have to load these modules before the methods that live in them can be used. So the first step is to figure out which these modules are and use() them.

しかしながら, mod_perl 2.0 はバージョン 1.0 がしていたよりもはるかに多くのモジュールにわたって機能を分割していて, それらに存在するメソッドを使う前にあなたはこれらのモジュールをロードしなければならないため, あなたがトライしてもあなたのコードが機能しないことはほとんど確実です。ですから最初のステップはこれらのモジュールがどれなのか探し出してそれを use() することです。
The ModPerl::MethodLookup module provided with mod_perl 2.0 allows you to find out which module contains the functionality you are looking for. Simply provide it with the name of the mod_perl 1.0 method that has moved to a new module, and it will tell you what the module is.

ModPerl::MethodLookup モジュールはあなたが見つけたい機能を含むモジュールをあなたが見つけ出せるように mod_perl 2.0 で提供されています。新しいモジュールに移動された mod_perl 1.0 メソッドの名前をシンプルに提供すると, そのモジュールが何かをあなたに伝えてくれます。
For example, let's say we have a mod_perl 1.0 code snippet:

例えば, 私たちが mod_perl 1.0 スニペットをもっているとします:

$r->content_type('text/plain');
$r->print("Hello cruel world!");

If we run this, mod_perl 2.0 will complain that the method content_type() can't be found. So we use ModPerl::MethodLookup to figure out which module provides this method. We can just run this from the command line:

私たちがこれを実行すると, メソッド content_type() が見つからないと mod_perl 2.0 は文句をいいます。
ですから私たちは ModPerl::MethodLookup を使ってこのメソッドを提供するモジュールを見つけ出します。私たちはコマンドラインからこれを実行するだけです:

% perl -MModPerl::MethodLookup -e print_method content_type

This prints:

これを出力します:

to use method 'content_type' add:
use Apache2::RequestRec ();

We do what it says and add this use() statement to our code, restart our server (unless we're using Apache2::Reload), and mod_perl will no longer complain about this particular method.

私たちがこれをいって私たちのコードにこの use() ステートメントの追加し, 私たちのサーバをリスタートすれば (私たちが Apache2::Reload を使っている場合を除き), mod_perl はこの特定のメソッドについてもう文句をいいません。
Since you may need to use this technique quite often you may want to define an alias. Once defined the last command line lookup can be accomplished with:

あなたはこのテクにっくを頻繁に使う必要があるのであなたはエイリアスを定義するとよいです。1 度定義すれば最後のコマンドラインでのルックアップはこれでできます:

% lookup content_type

ModPerl::MethodLookup also provides helper functions for finding which methods are defined in a given module, or which methods can be invoked on a given object.

ModPerl::MethodLookup は与えられたモジュールでメソッドが定義されているか, または与えられたオブジェクトでメソッドが呼び出せるかを見つけるためのヘルパファンクション (# lookup_module(), lookup_object()) も提供します。


複数のパッケージに存在するメソッドを扱う : Handling Methods Existing In More Than One Package


Some methods exists in several classes. For example this is the case with the print() method. We know the drill:

一部のメソッドはいくつかのクラスに存在します。例えばこれは print() メソッドのケースです。私たちはドリルを知っています:

% lookup print

This prints:

これは出力します:

There is more than one class with method 'print'
try one of:
use Apache2::RequestIO ():
use Apache2::Filter ():

So there is more than one package that has this method. Since we know that we call the print() method with the $r object, it must be the Apache2::RequestIO module that we are after. Indeed, loading this module solves the problem.

このようにこのメソッドをもつパッケージは複数あります。私たちは私たちが print() メソッドを $r オブジェクトで呼ぶことを知っているので, 私たちは後で Apache2::RequestIO モジュールが必要とします。確かに, このモジュールをロードすると問題は解決します。


プログラムで ModPerl::MethodLookup を使う : Using ModPerl::MethodLookup Programmatically


The issue of picking the right module, when more than one matches, can be resolved when using ModPerl::MethodLookup programmatically -- lookup_method accepts an object as an optional second argument, which is used if there is more than one module that contains the method in question. ModPerl::MethodLookup knows that Apache2::RequestIO and and Apache2::Filter expect an object of type Apache2::RequestRec and type Apache2::Filter respectively. So in a program running under mod_perl we can call:

複数マッチするときに, 正しいモジュールをピックする課題は, ModPerl::MethodLookup をプログラムで使うと解決できます -- lookup_method は当該のメソッドを含むモジュールが複数ある場合に使われ, これはオプションの第 2 引数としてオブジェクトを受けつけます。ModPerl::MethodLooku は Apache2::RequestIO と Apache2::Filter がそれぞれ Apache2::RequestRec タイプと Apache2::Filter タイプのオブジェクトを期待することを知っています。
ですから mod_perl のもとで走っているプログラムで私たちは呼べます:

ModPerl::MethodLookup::lookup_method('print', $r);

Now only one module will be matched.

これでひとつだけのモジュールがマッチします。
This functionality can be used in AUTOLOAD, for example, although most users will not have a need for this robust of solution.

この機能は, 例えば (# Perl の) AUTOLOAD でも使えます, もっともほとんどのユーザはこの堅牢なソリューションを必要としません。


mod_perl 2.0 モジュールをすべてプレローディングする : Pre-Loading All mod_perl 2.0 Modules


Now if you use a wide range of methods and functions from the mod_perl 1.0 API, the process of finding all the modules that need to be loaded can be quite frustrating. In this case you may find the function preload_all_modules() to be the right tool for you. This function preloads all mod_perl 2.0 modules, implementing their API in XS.

いまあなたが mod_perl 1.0 API からの広範囲なメソッドやファンクションを使う場合, ロードする必要があるすべてのモジュールを見つけるプロセスは極めてイライラさせます。このケースでは preload_all_modules() があなたにとって正しいツールになることをあなたは見つけるはずです。このファンクションはすべての mod_perl 2.0 モジュールをプレロードし, それらの API を XS で実装します。
While useful for testing and development, it is not recommended to use this function in production systems. Before going into production you should remove the call to this function and load only the modules that are used, in order to save memory.

テストと開発に役立ちますが, プロダクション環境でこのファンクションを使うことは推奨しません。プロダクションに行く前にあなたはメモリを節約するために, このファンクションの呼びだしを削除し使われるモジュールのみをロードするようにしたほうがよいです。
CPAN module developers should not be tempted to call this function from their modules, because it prevents the user of their module from optimizing her system's memory usage.

CPAN モジュールの開発者はあなた方のモジュールのユーザが彼女たちのシステムのメモリ使用法を最適化することを阻むことになるためあなた方のモジュールからこのファンクションを呼ぼうとしないでください。


失われた and 修正された mod_perl 1.0 のメソッドとファンクションを扱う : Handling Missing and Modified mod_perl 1.0 Methods and Functions


The mod_perl 2.0 API is modeled even more closely upon the Apache API than was mod_perl version 1.0. Just as the Apache 2.0 API is substantially different from that of Apache 1.0, therefore, the mod_perl 2.0 API is quite different from that of mod_perl 1.0. Unfortunately, this means that certain method calls and functions that were present in mod_perl version 1.0 are missing or modified in mod_perl 2.0.

mod_perl 2.0 API は mod_perl 1.0 よりも Apache API に近くモデル化されています。したがって, Apache 2.0 API が Apache 1.0 のそれと実質的に異なるのと同じく, mod_perl 2.0 API は mod_perl 1.0 のそれから大きく異なります。残念ですが, これは mod_perl バージョン 1.0 で存在していた特定のメソッドコールやファンクションが mod_perl 2.0 で失われているか修正されていることを意味します。
If mod_perl 2.0 tells you that some method is missing and it can't be found using ModPerl::MethodLookup, it's most likely because the method doesn't exist in the mod_perl 2.0 API. It's also possible that the method does still exist, but nevertheless it doesn't work, since its usage has changed (e.g. its prototype has changed, or it requires different arguments, etc.).

mod_perl 2.0 が一部のメソッドが失われていて ModPerl::MethodLookup を使っても見つからないとあなたに伝えた場合, それは多分そのメソッドが mod_perl 2.0 API で存在しないからです。
そのメソッドがまだ存在するにも関わらず, 使用法が変更されたがゆえに, 機能していない可能性もあります (e.g. プロトタイプが変更されている, またはそれが異なる引数を必要としている, etc.)。
In either of these cases, refer to the backwards compatibility document for an exhaustive list of API calls that have been modified or removed.

いずれのケースでも, 修正されたり削除された API の徹底したリストのために後方互換性のドキュメントを参照してください。


もう存在しないメソッド : Methods that No Longer Exist


Some methods that existed in mod_perl 1.0 simply do not exist anywhere in version 2.0 and you must therefore call a different method o methods to get the functionality you want.

For example, suppose we have a mod_perl 1.0 code snippet:

シンプルに mod_perl 1.0 で存在した一部のメソッドはバージョン 2.0 ではどこにも存在しませんのであなたはあなたが要する機能を得るために異なるメソッドを呼ばなければなりません。

例えば, 私たちは mod_perl 1.0 の次のコードスニペットをもってるとします:

$r->log_reason("Couldn't open the session file: $@");

If we try to run this under mod_perl 2.0 it will complain about the call to log_reason(). But when we use ModPerl::MethodLookup to see which module to load in order to call that method, nothing is found:

もし私たちが mod_perl 2.0 のもとでこれの実行をトライすると log_reason() の呼び出しについて文句をいいます。しかし私たちはそのメソッドを呼ぶためにどのモジュールをロードするかを見るために ModPerl::MethodLookup を使っても, 何も見つかりません:

% perl -MModPerl::MethodLookup -le \
'print((ModPerl::MethodLookup::lookup_method(shift))[0])' \
log_reason

This prints:

これを出力します:

don't know anything about method 'log_reason'

Looks like we are calling a non-existent method! Our next step is to refer to the backwards compatibility document, wherein we find that as we suspected, the method log_reason() no longer exists, and that instead we should use the other standard logging functions provided by the Apache2::Log module.

私たちは存在しないメソッドを呼び出しているようだ ! 私たちの次のステップは後方互換性のドキュメントを参照することで, そこで私たちは私たちの予想したとおり, メソッド log_reason() がもう存在せず, かわりに私たちは Apache2::Log モジュールによって提供される他の標準ロギングファンクションを使わなければならないことを見つけます。


使用法が変更されたメソッド : Methods Whose Usage Has Been Modified


Some methods still exist, but their usage has been modified, and your code must call them in the new fashion or it will generate an error. Most often the method call requires new or different arguments.

For example, say our mod_perl 1.0 code said:

いくつかのメソッドはまだ存在していますが, それらの使用法は修正されていて, あなたのコードは新しい流儀でそれらを呼ばなければならずそうでなければエラーが生成されます。ほとんどのメソッドコールは新しいか異なる引数を要求します。

例えば, 私たちの mod_perl 1.0 のコードが次の言ったとします:

$parsed_uri = Apache2::URI->parse($r, $r->uri);

This code causes mod_perl 2.0 to complain first about not being able to load the method parse() via the package Apache2::URI. We use the tools described above to discover that the package containing our method has moved and change our code to load and use APR::URI:

このコードにより mod_perl 2.0 はパッケージ Apache2::URI を介してメソッド parse() をロードできないことについて最初に文句をいいます。私たちは私たちのメソッドを含んだパッケージが移動されたことを発見するために上記で説明したツールを使い APR::URI をロードして使うために私たちのコードを変更します:

$parsed_uri = APR::URI->parse($r, $r->uri);

But we still get an error. It's a little cryptic, but it gets the point across:

しかし私たちはまだエラーをえます。それはすこし謎めいていますが, 言いたいことはわかります:

p is not of type APR::Pool at /path/to/OurModule.pm line 9.

What this is telling us is that the method parse requires an APR::Pool object as its first argument. (Some methods whose usage has changed emit more helpful error messages prefixed with "Usage: ...") So we change our code to:

これが私たちに伝えるのはメソッドのパースが最初の引数として APR::Pool オブジェクトを必要とすることです。(使用法が変更されたいくつかのメソッドはプレフィクス "Usage: ..." でより役立つエラーメッセージを発します) ですから私たちは私たちのコードを次のように変更します:

$parsed_uri = APR::URI->parse($r->pool, $r->uri);

and all is well in the world again.

そして再び世界は順調です。


特定の mod_perl バージョンを要求する : Requiring a specific mod_perl version.


To require a module to run only under 2.0, simply add:

2.0 のもとでのみ走るようにモジュールに要求するためには, シンプルに追加します:

use mod_perl 2.0;

META: In fact, before 2.0 is released you really have to say:

META: 実際に, 2.0 がリリースされる前にあなたは本当に言わなければなりません (# 2.0 リリース前の時点で 1.X を使っていた場合はこれを追加しないとおそらく問題が発生する):

use mod_perl 1.99;

And you can even require a specific version (for example when a certain API has been added only starting from that version). For example to require version 1.99_08, you can say:

あなたは特定のバージョンでさえも要求できます (例えば特定の API がそのバージョンからのみ追加されているときに)。例えばバージョン 1.99_08 を要求するために, あなたはいえます:

use mod_perl 1.9908;



モジュール名は変更するべき ? : Should the Module Name Be Changed?


If it is not possible to make your code run under both mod_perl versions (see below), you will have to maintain two separate versions of your own code. While you can change the name of the module for the new version, it's best to try to preserve the name and use some workarounds.

META: need to discuss this more.

もしあなたのコードが両方の mod_perl バージョン (以下を参照) のもとで実行するようにできないなら, あなたはあなたの独自コードを 2 つに分けたバージョンをメンテしなければなりません。あなたは新しいバージョンのためにモジュールの名前を変更できますが, 名前を保持していくつかの回避策の利用をトライすることがベストです。

META: これについてより論じる必要がある。


チュートリアルとして Apache2::compat を使う : Using Apache2::compat As a Tutorial


Even if you have followed the recommendation and eschewed use of the Apache2::compat module, you may find it useful to learn how the API has been changed and how to modify your own code. Simply look at the Apache2::compat source code and see how the functionality should be implemented in mod_perl 2.0.

あなたが推奨に従い Apache2::cmpat モジュールの利用を控えたとしても, あなたはどのように API が変更されていてどのようにあなたの独自のコードを修正するかを学ぶことが役立つことを見つけるでしょう。シンプルに Apache2::compat のソースコードを確認して mod_perl 2.0 で機能がどのように実装されているべきかをみてください。
For example, mod_perl 2.0 doesn't provide the Apache->gensym method. As we can see if we look at the Apache2/compat.pm source, the functionality is now available via the core Perl module Symbol and its gensym() function. (Since mod_perl 2.0 works only with Perl versions 5.6 and higher, and Symbol.pm is included in the core Perl distribution since version 5.6.0, there was no reason to keep providing Apache->gensym.)

例えば, mod_perl 2.0 は Apache->gensys メソッドを提供していません。私たちが Apache2/compat.pm ソースを確認すればみれるように, その機能はコア Perl モジュール Symbol とその gensym() ファンクションを介して利用可能になっています。 ( mod_perl 2.0 は Perl バージョン 5.6 以降でのみ機能し, Symbol.pm はバージョン 5.6.0 からのコア Perl ディストリビューションに含まれているため, Apache->gensym の提供を維持する理由がありませんでした。)
So if the original code looked like:

ですからオリジナルコードが次のようになっているなら:

my $fh = Apache->gensym;
open $fh, $file or die "Can't open $file: $!";

in order to port it mod_perl 2.0 we can write:

これを mod_perl 2.0 に移植するために私たちはこう書けます:

my $fh = Symbol::gensym;
open $fh, $file or die "Can't open $file: $!";

Or we can even skip loading Symbol.pm, since under Perl version 5.6 and higher we can just do:

または私たちは Symbol.pm のロードをスキップすることさえできます, Perl バージョン 5.6 以降のもとで私たちは単にこれだけを行えるからです (# Symbol::gensym は匿名のグロブを作成しそれへのリファレンスを返す。ファイル|ディレクトリハンドルとして使うことができる。こういうときに便利 (perlfaq8) なようす):

open my $fh, $file or die "Can't open $file: $!";

(# open の引数上で "my $fh" として直接レキシカルのスカラを作成してある)


Apache::MP3 はどうやって mod_perl 2.0 移植されたか : How Apache::MP3 was Ported to mod_perl 2.0


Apache::MP3 is an elaborate application that uses a lot of mod_perl API. After porting it, I have realized that if you go through the notes or even better try to do it by yourself, referring to the notes only when in trouble, you will most likely be able to port any other mod_perl 1.0 module to run under mod_perl 2.0. So here the log of what I have done while doing the porting.

Apache::MP3 は多くの mod_perl API を使った複雑なアプリケーションです。これを移植した後, もしあなたがこのノートを読みかつトラブルがあったときにこのノートを参照して, あなた自身でより良くこれをやろうとすれば, あなたが他の mod_perl 1.0 モジュールを mod_perl 2.0 の下で走らせるために移植できる可能性が高いことに私は気がつきました。ですからこちらは私がその移植をしていたときの記録です。
Please notice that this tutorial should be considered as-is and I'm not claiming that I have got everything polished, so if you still find problems, that's absolutely OK. What's important is to try to learn from the process, so you can attack other modules on your own.

このチュートリアルはそのママ (# as-is)だと見做されるべきで私のすべてが完成されていると私は主張していないことに注意して下さい, ですからあなたが問題を見つけても, それはまったく OK なことです。重要なことはこのプロセスから学びトライすることで, あなたがあなた独自に他のモジュールにアタックすることです。
I've started to work with Apache::MP3 version 3.03 which you can retrieve from Lincoln's CPAN directory: http://search.cpan.org/CPAN/authors/id/L/LD/LDS/Apache-MP3-3.03.tar.gz Even though by the time you'll read this there will be newer versions available it's important that you use the same version as a starting point, since if you don't, the notes below won't make much sense.

Lincoln の CPAN ディレクトリ: http://search.cpan.org/CPAN/authors/id/L/LD/LDS/Apache-MP3-3.03.tar.gz からあなたが取得出来る Apache::MP3 バージョン 3.03 で私は仕事をはじめました。あなたがこれを読む頃には利用可能な新しいバージョンがあるでしょうが重要なのはあなたがスタート地点として同じバージョンを使うことで, あなたがそうしないと, 以下のノートは意味がなくなってしまいます。


準備 : Preparations


First of all, I scratched most of mine httpd.conf and startup.pl leaving the bare minimum to get mod_perl started. This is needed to ensure that once I've completed the porting, the module will work correct on other users systems. For example if my httpd.conf and startup.pl were loading some other modules, which in turn may load modules that a to-be-ported module may rely on, the ported module may work for me, but once released, it may not work for others. It's the best to create a new httpd.conf when doing the porting putting only the required bits of configuration into it.

まずはじめに, 私は mod_perl をスタートさせるための最小限のままにして私の httpd.conf と startup.pl のほとんどをスクラッチしました。これは私がこの移植を完了した際に, 他のユーザのシステム上でモジュールが正しく機能することを確実にするために必要です。例えばもし私の httpd.conf と startup.pl が他のモジュールをロードしていて, 移植予定のモジュールが頼るモジュールをロードしていると, 移植されたモジュールは私のためには動くかもしれませんが, リリースされると, それは他で動かないかもしれません。移植するときは必要とされる少しの構成をその中に置いた新しい httpd.conf を作成するのがベストです。


httpd.conf


Next, I configure the Apache2::Reload module, so we don't have to constantly restart the server after we modify Apache::MP3. In order to do that add to httpd.conf:

次に, 私は Apache2::Reload モジュールを構成するので, 私たちは私たちが Apache::MP3 を修正した後で毎回サーバを再起動しなくてもよくなります。これをやるために httpd.conf に次を追加します:

PerlModule Apache2::Reload
PerlInitHandler Apache2::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "ModPer::* Apache2::*"
PerlSetVar ReloadConstantRedefineWarnings Off

You can refer to the Apache2::Reload manpage for more information if you aren't familiar with this module. The part:

もしあなたがこのモジュールに慣れていないならあなたは詳細のためにApache2::Reload man ページを参照できます。このパートは:

PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "ModPerl::* Apache::*"

tells Apache2::Reload to monitor only modules in the ModPerl:: and Apache:: namespaces. So Apache::MP3 will be monitored. If your module is named Foo::Bar, make sure to include the right pattern for the ReloadModules directive. Alternatively simply have:

Apache2::Reload に ModPerl:: と Apache:: の名前空間のモジュールのみをモニタするように伝えます。ですから Apache::MP3 はモニタされます。もしあなたのモジュールが Foo::Bar と名付けられているなら, ReloadModules ディレクティブの右側のパターンに含めるようにしてください。あるいは単純に:

PerlSetVar ReloadAll On

which will monitor all modules in %INC, but will be a bit slower, as it'll have to stat(3) many more modules on each request.

これは %INC のすべてのモジュールをモニタします, しかしこれは各リクエストでより多くのモジュールを stat(3) しなければならないので, 少し遅くなります。
Finally, Apache::MP3 uses constant subroutines. Because of that you will get lots of warnings every time the module is modified, which I wanted to avoid. I can safely shut those warnings off, since I'm not going to change those constants. Therefore I've used the setting

最後に, Apache::MP3 は定数サブルーチンを使います。このためモジュールが修正されるたびにあなたはたくさんの警告をうけますが, 私はそれを回避したいと思いました。私はこれらの定数を変更しないので, 私はこれらの警告を安全に遮断できます。ですから私はこの設定を使います

PerlSetVar ReloadConstantRedefineWarnings Off

If you do change those constants, refer to the section on ReloadConstantRedefineWarnings.

あなたがそれらの定数を変更するなら, ReloadConstantRedefineWarnings のセクションを参照してください。
Next I configured Apache::MP3. In my case I've followed the Apache::MP3 documentation, created a directory mp3/ under the server document root and added the corresponding directives to httpd.conf.

つぎに私は Apache::MP3 を構成しました。私のケースでは私は Apache::MP3 のドキュメントにしたがって, サーバのドキュメントルートの下に mp3/ ディレクトリを作成して httpd.conf に対応するディレクティブを追加しました。
Now my httpd.conf looked like this:

これで私の httpd.conf はこのように見えます:

#file:httpd.conf
#---------------
Listen 127.0.0.1:8002
#... standard Apache configuration bits omitted ...
#... 標準の Apache 構成は少し省略しています ...

LoadModule perl_module modules/mod_perl.so

PerlSwitches -wT

PerlRequire "/home/httpd/2.0/perl/startup.pl"

PerlModule Apache2::Reload
PerlModule Apache2::Reload
PerlInitHandler Apache2::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "ModPerl::* Apache::*"
PerlSetVar ReloadConstantRedefineWarnings Off

AddType audio/mpeg mp3 MP3
AddType audio/playlist m3u M3U
AddType audio/x-scpls pls PLS
AddType application/x-ogg ogg OGG
<Location /mp3>
SetHandler perl-script
PerlResponseHandler Apache::MP3
PerlSetVar PlaylistImage playlist.gif
PerlSetVar StreamBase http://localhost:8002
PerlSetVar BaseDir /mp3
</Location>



startup.pl


Since chances are that no mod_perl 1.0 module will work out of box without at least preloading some modules, I've enabled the Apache2::compat module. Now my startup.pl looked like this:

おそらく少なくともいくつかのモジュールをプレロードしないと mod_perl 1.0 モジュールがすぐに機能しないはずなので, 私は Apache2::compat モジュールを有効にしました。これで私の startup.pl はこのようになりました:

#file:startup.pl
#---------------
use lib qw(/home/httpd/2.0/perl);
use Apache2::comat;



Apache/MP3.pm


Before I even started porting Apache::MP3, I've added the warnings pragma to Apache/MP3.pm (which wasn't there because mod_perl 1.0 had to work with Perl versions prior to 5.6.0, which is when the warnings pragma was added):

私が Apache::MP3 の移植をまだはじめるまえに, 私は Apache/MP3.pm に warnings プラグマを追加しました (mod_perl 1.0 は, warnings プラグラマが追加された Perl バージョン 5.6.0 以前で機能すればよかったのでこれがありませんでした):

#file:apache_mp3_prep.diff
--- Apache/MP3.pm.orig 2003-06-03 18:44:21.000000000 +1000
+++ Apache/MP3.pm 2003-06-03 18:44:47.000000000 +1000
@@ -4,2 +4,5 @@
use strict;
+use warnings;
+no warnings 'redefine'; # XXX: remove when done with porting
+

From now on, I'm going to use unified diffs which you can apply using patch(1). Though you may have to refer to its manpage on your platform since the usage flags may vary. On linux I'd apply the above patch as:

これ以降, 私は unified 形式の diff を使いますのであなたは patch(1) を使って適用できます。ただしフラグの使い方が変わっているかもしれないのであなたはあなたのプラットフォームでその man ページを参照した方がよいです。linux 上で私は上記パッチを次のように適用します:

% cd ~/perl/blead-ithread/lib/site_perl/5.9.0/
% patch -p0 < apache_mp3_prep.diff

(note: I've produced the above patch and one more below with diff -u1, to avoid the RCS Id tag geting into this document. Normally I produce diffs with diff -u which uses the default context of 3.)

(note: RCS Id タグがこのドキュメントに入ることを回避するために, 私は上記パッチと以下のひとつ以上を diff -u1 で生成しました。普通私はデフォルトのコンテキスト 3 を使う diff -u で diff を生成します。)
assuming that Apache/MP3.pm is located in the directory ~/perl/blead-ithread/lib/site_perl/5.9.0/.

Apache/MP3.pm がディレクトリ ~/perl/blead-ithread/lib/site_perl/5.9.0/ に配置されていると仮定しています。
I've enabled the warnings pragma even though I did have warnings turned globally in httpd.conf with:

私はこれで httpd.conf にグローバルで warnings をいれていますが (# 上記 MP3.pm でも) 私は warnings プラグマを有効にしています:

PerlSwitches -wT

it's possible that some badly written module has done:

一部の行儀の悪いモジュールがこのように書かれているかもしれません:

$^W = 0;

without localizing the change, affecting other code. Also notice that the taint mode was enabled from httpd.conf, something that you shouldn't forget to do.

ローカライズなしの変更は, 他のコードにも影響します。また taint (# 汚染) モードが httpd.conf から有効にされていることも注意して下さい, これを行うことを忘れてはいけません。
I have also told the warnings pragma not to complain about redefined subs via:

また私は次のものを介して sub (# サブルーチン) の再定義については文句をいわないように warnings プラグマにいいました:

no warnings 'redefine'; # XXX: remove when done with porting

I will remove that code, once porting is completed.

私は移植が完了したら, このコードを削除します。
At this point I was ready to start the porting process and I have started the server.

この時点で私は移植作業をスタートするための準備ができて私はサーバを起動しました。

% hup 2

I'm using the following aliases to save typing:

私は次のエイリアスを使ってタイピングを節約しています:

alias err2 "tail -f ~/httpd/prefork/logs/error_log"
alias acc2 "tail -f ~/httpd/prefork/logs/access_log"
alias stop2 "~/httpd/prefork/bin/apachectl stop"
alias start2 "~/httpd/prefork/bin/apachectl start"
alias restart2 "~/httpd/prefork/bin/apachectl restart"
alias graceful2 "~/httpd/prefork/bin/apachectl graceful"
alias hup2 "stop2; sleep 3; start2; err2"

(I also have a similar set of aliases for mod_perl 1.0)

(私は mod_perl 1.0 のために同様のエイリアスのセットももっています)


Apache2::compat で移植する : Porting with Apache2::compat


I have configured my server to listen on port 8002, so I issue a request http://localhost:8002/mp3/ in one console:

私は私のサーバをポート 8002 をリッスンするように構成したので, 私は 1 つのコンソールでリクエスト http://localhost:8002/mp3/ を発行します:

% lynx --dump http://localhost:8002/mp3/

keeping the error_log open in the other:

他 (# のコンソール) で error_log をオープンしたままにします:

% err2

which expands to:

これはこのように展開されます (# see 上記エイリアス):

% tail -f ~/httpd/prefork/logs/error_log

When the request is issued, the error_log file tells me:

リクエストが発行されると, error_log ファイルは私にこれを伝えてくれます:

[Thu Jun 05 15:29:45 2003] [error] [client 127.0.0.1]
Usage: Apache2::RequestRec::new(classname, c, base_pool=NULL)
at .../Apache/MP3.pm line 60.

Looking at the code:

コードを確認します:

58: sub handler ($$) {
59: my $class = shift;
60: my $obj = $class->new(@_) or die "Can't create object: $!";

The problem is that handler wasn't invoked as method, but had $r passed to it (we can tell because new() was invoked as Apache2::RequestRec::new(), whereas it should have been Apache::MP3::new(). Why Apache::MP3 wasn't passed as the first argument? I go to the mod_perl 1.0 backward compatibility document and find that method handlers are now marked using the method subroutine attribute. So I modify the code:

問題はハンドラがメソッドとして呼び出されていないのに, それに $r を渡していることです (私たちはこれは Apache2::MP3::new() なのに, Apache2::RequestRec::new() として, new() が呼びだされているからだと分かります。なぜ Apache::MP3 が最初の引数として渡されないのか ? 私は mod_perl 1.0 の backward compatibility (# 後方互換の) ドキュメントにいきメソッドハンドラが今は method サブルーチンアトリビュートを使ってマークされていることを見つけます。ですから私はコードを修正します:

--- Apache/MP3.pm.0 2003-06-05 15:29:19.000000000 +1000
+++ Apache/MP3.pm 2003-06-05 15:38:41.000000000 +1000
@@ -55,7 +55,7 @@
my $NO = '^(no|false)$'; # regular expression
my $YES = '^(yes|true)$'; # regular expression

-sub handler ($$) {
+sub handler : method {
my $class = shift;
my $obj = $class->new(@_) or die "Can't create object: $!";
return $obj->run();

and issue the request again (no server restart needed).

そして再びリクエストを発行します (サーバのリスタートは不要です)。
This time we get a bunch of looping redirect responses, due to a bug in mod_dir which kicks in to handle the existing dir and messing up with $r->path_info keeping it empty at all times. I thought I could work around this by not having the same directory and location setting, e.g. by moving the location to be /songs/ while keeping the physical directory with mp3 files as $DocumentRoot/mp3/, but Apache::MP3 won't let you do that. So a solution suggested by Justin Erenkrantz is to simply shortcut that piece of code with:

今度は既存の dir の処理のために起動する mod_dir のバグとそれを $r->path_info でいじって常にそれを空にしていることが原因で, 私たちはループした多数のリダイレクトレスポンスを得ます。私は同じディレクトリとロケーションの設定をもたないことでこれ回避できると私は思いました, e.g. mp3 ファイルの物理ディレクトリは $DocumentRoot/mp3/ として維持したまま /songs/ にロケーションを移動することでと, しかし Apache::MP3 はそれをあなたにさせてくれません。ですから Justin ErenKrantz により提案されたソリューションはシンプルにコードのその部分をこのようにショートカットするものです:

--- Apache/MP3.pm.1 2003-06-06 14:50:59.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 14:51:11.000000000 +1000
@@ -253,7 +253,7 @@
my $self = shift;
my $dir = shift;

- unless ($self->r->path_info){
+ unless ($self->r->path_info eq ''){
#Issue an external redirect if the dir isn't tailed with a '/'
#dir の末尾が '/' でければ外部リクエストを発行する
my $uri = $self->r->uri;
my $query = $self->r->args;

which is equivalent to removing this code, until the bug is fixed (it was still there as of Apache 2.0.46). But the module still works without this code, because if you issue a request to /mp3 (w/o trailing slash) mod_dir, will do the redirect for you, replacing the code that we just removed. In any case this got me past this problem.

これはこのバグがフィックスされるまで, このコードを削除したことと同等です (これは Apache 2.0.46 の時点でまだあります)。しかしあなたが /mp3 (末尾のスラッシュなし) mod_dir にリクエストを発行すると, 私たちがちょうど削除したコードを置き換えて, あなたのためにリダイレクトするため, モジュールはこのコードが無くてもまだ動きます。いずれにせよこれは私にこの問題をパスさせてくれました。
Since I have turned on the warnings pragma now I was getting loads of uninitialized value warnings from $r->dir_config() whose return value were used without checking whether they are defined or not. But you'd get them with mod_perl 1.0 as well, so they are just an example of not-so clean code, not really a relevant obstacle in my pursuit to port this module to mod_perl 2.0. Unfortunately they were cluttering the log file so I had to fix them. I've defined several convenience functions:

私は warnings プラグマを on にしてからは戻り値が定義されているかどうかをチェックせずに使われている $r->dir_config() からの未初期化の値の (# uninitialized value) 警告を私は注意してみるようにしました。しかし mod_perl 1.0 でもあなたはそれを受けとるので, これらは単にそれほどクリーンでないコードの例であり, このモジュールを mod_perl 2.0 に移植するという私の探究に関連する障害ではありません。残念ながら慌ただしいログファイルだったので私はそれらを修正しなければなりませんでした。私は便利なファンクションをいくつか定義しました:

sub get_config {
my $val = shift->r->dir_config(shift);
return defined $val ? $val : '';
}

sub config_yes { shift->get_config(shift) !~ /$YES/oi; }
sub config_no { shift->get_config(shift) !~ /$NO/oi; }

and replaced them as you can see in this patch: code/apache_mp3_2.diff, it was 194 lines long so I didn't inline it here, but it was quick to create with a few regexes search-n-replace manipulations in xemacs.

このパッチで見れるようにこれらをリプレイスしました: code/apache_mp3_2.diff (# diff ファイルへのダイレクトリンク, 上記で定義した get_config() を各所で dir_config() の代替として使っている), これは 194 行の長さだったので私はここにインライン化はしませんでしたが, xemacs のいくつかの正規表現 serche-n-replace の操作でクイックに作成出来ました。
Now I have the browsing of the root /mp3/ directory and its sub-directories working. If I click on 'Fetch' of a particular song it works too. However if I try to 'Stream' a song, I get a 500 response with error_log telling me:

これで私は root の /mp3/ ディレクトリとそのサブディレクトリの閲覧できるようになりました。私が特定の曲の 'Ferch' をクリックすればそれも機能します。しかし曲の 'Stream' を試みると, error_log が私がレスポンス 500 を受けていることを私に教えてくれます。

[Fri Jun 06 15:33:33 2003] [error] [client 127.0.0.1] Bad arg length
for Socket::unpack_sockaddr_in, length is 31, should be 16 at
.../5.9.0/i686-linux-thread-multi/Socket.pm line 370.

It would be certainly nice for Socket.pm to use Carp::carp() instead of warn() so we will know where in the Apache::MP3 code this problem was triggered. However reading the Socket.pm manpage reveals that sockaddr_in() in the list context is the same as calling an explicit unpack_sockaddr_in(), and in the scalar context it's calling pack_sockaddr_in(). So I have found sockaddr_in was the only Socket.pm function used in Apache::MP3 and I have found this code in the function is_local():

Socket.pm が warn() のかわりに Cparp::carp() を使うのはとてもナイスで Apache::MP3 コードでどこがこの問題のトリガになっているかを私たちは知ることが出来ます。けれども Soket.pm man ページを読むとリストコンテキストでの sockaddr_in() は明示的な unpack_sockaddr_in() の呼びだしとスカラコンテキストでは pack_sockaddr_in() と同じだと明らかになります。そのため私は Apache::MP3 で使われている Socket.pm のファンクションが sockaddr_in だけであることを見つけてファンクション is_local() のこのコードを私は見つけました:

my $r = $self->r;
my ($serverport,$serveraddr) = sockaddr_in($r->connection->local_addr);
my ($remoteport,$remoteaddr) = sockaddr_in($r->connection->remote_addr);
return $serveraddr eq $remoteaddr;

Since something is wrong with function calls $r->connection->local_addr and/or $r->connection->remote_addr and I referred to the mod_perl 1.0 backward compatibility document and found the relevant entry on these two functions. Indeed the API have changed. Instead of returning a packed SOCKADDR_IN string, Apache now returns an APR::SockAddr object, which I can query to get the bits of information I'm interested in. So I applied this patch:

$r->connection->local_addr and/or $r->connection->remote_addr のファンクションコールで何かが間違っているので私は the mod_perl 1.0 backward compatibility document を参照してこれら 2 つのファンクションに関連するエントリを見つけました。確かに API は変更されていました。パックされた SOCKADDR_IN 文字列を返す替わりに, Apache は APR::SockAddr オブジェクトを返すようになり, これで私は私が興味ある情報の一部を取得するためにクエリができます。ですからわたしはこのパッチを適用しました:

--- Apache/MP3.pm.3 2003-06-06 15:36:15.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 15:56:32.000000000 +1000
@@ -1533,10 +1533,9 @@
# allows the player to fast forward, pause, etc.
sub is_local {
my $self = shift;
- my $r = $self->r;
- my ($serverport,$serveraddr) = sockaddr_in($r->connection->local_addr);
- my ($remoteport,$remoteaddr) = sockaddr_in($r->connection->remote_addr);
- return $serveraddr eq $remoteaddr;
+ my $c = $self->r->connection;
+ require APR::SockAddr;
+ return $c->local_addr->ip_get eq $c->remote_addr->ip_get;
}

# Check if the requesting client is on the local network, as defined by

And voila, the streaming option now works. I get a warning on 'Use of uninitialized value' on line 1516 though, but again this is unrelated to the porting issues, just a flow logic problem, which wasn't triggered without the warnings mode turned on. I have fixed it with:

これで, ストリーミングオプションが機能するようになりました。1516 行目を通じて 'Use of uninitialized value (非初期化値)' の警告を受けますが, これはやはりこの移植には無関係な問題で, warnings モードを on にしなければトリガされない, 単なるロジックの流れの問題です。私はこれでフィックスしました:

--- Apache/MP3.pm.4 2003-06-06 15:57:15.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 16:04:48.000
@@ -1492,7 +1492,7 @@
my $suppress_auth = shift;
my $r = $self->r;

- my $auth_info;
+ my $auth_info = '';
# the check for auth_name() prevents an anno
# the apache server log when authentication
if ($r->auth_name && !$suppress_auth) {
@@ -1509,10 +1509,9 @@
}

my $vhost = $r->hostname;
- unless ($vhost) {
- $vhost = $r->server->server_hostname;
- $vhost .= ':' . $r->get_server_port unless
- }
+ $vhost = $r->server->server_hostname unless
+ $vhost .= ':' . $r->get_server_port unless $
+
return "http://${auth_info}${vhost}";
}

This completes the first part of the porting. I have tried to use all the visible functions of the interface and everything seemed to work and I haven't got any warnings logged. Certainly I may have missed some usage patterns which may be still problematic. But this is good enough for this tutorial.

これが移植の最初の部分の完了です。私はインターフェイスの表示されている機能のすべて使うことを試みてすべてが機能しているように見えたし私は何の警告ログも受けとっていません。確かに私はまだ問題があるかもしれないいくつかの使用パターンを見逃したかもしれません。しかしこのチュートリアルではこれで十分です。


Apache2::compat の依存関係を取り除く : Getting Rid of the Apache2::compat Dependency


The final stage is going to get rid of Apache2::compat since this is a CPAN module, which must not load Apache2::compat on its own. I'm going to make Apache::MP3 work with mod_perl 2.0 all by itself.

最後のステージはこれが CPAMN モジュールなのでこれがこれ独自に Apache2::compat を決してロードしないように, Apache2::compat の除去をすることです。私は mod_perl 2.0 で Apache::MP3 がすべてそれ自身で機能するようにします。
The first step is to comment out the loading of Apache2::compat in startup.pl:

最初のステップは startup.pl での Apache2::compat の読み込みをコメントアウトすることです:

#file:startup.pl
#---------------
use lib qw(/home/httpd/2.0/perl);
#use Apache2::compat ();



Apache2::compat がロードされていないことを確認する : Ensuring that Apache2::compat is not loaded


The second step is to make sure that Apache2::compat doesn't get loaded indirectly, through some other module. So I've added this line of code to Apache/MP3.pm:

2 番目のステップは何か他のモジュールを通じて, Apache2::compat が間接的に読み込まれないことを確認することです。ですから私は Apache/MP3.pm にこのコードの行を追加しました:

--- Apache/MP3.pm.5 2003-06-06 16:17:50.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 16:21:14.000000000 +1000
@@ -3,2 +3,6 @@

+BEGIN {
+ die "Apache2::compat is loaded loaded" if $INC{'Apache2/compat.pm'};
+}
+
use strict;

and indeed, even though I've commented out the loading of Apache2::compat from startup.pl, this module was still getting loaded. I knew that because the request to /mp3 were failing with the error message:

そして実際, 私は startup.pl からの Apache2::compat の読み込みをコメントアウトしたにもかかわらず, このモジュールはまだ読み込んでいました。私は /mp3 へのリクエストがこのエラーメッセージで失敗したのでそれを知りました:

Apache2::compat is loaded loaded at ...

There are several ways to find the guilty party, you can grep(1) for it in the perl libraries, you can override CORE::GLOBAL::require() in startup.pl:

犯人を見つけるための方法はいくつかあり, あなたは perl ライブラリでそのために grep(1) できて, あなたは startup.pl で CORE::GLOBAL::require() を上書きできます:

BEGIN {
use Carp;
*CORE::GLOBAL::require = sub {
Carp::cluck("Apache2::compat is loaded") if $_[0] =~ /compat/;
CORE::require(@_);
};
}

or you can modify Apache2/compat.pm and make it print the calls trace when it gets compiled:

またはあなたは Apache2/compat.pm を修正してそれがコンパイルされたときにコールトレースを出力するようにできます:

--- Apache2/compat.pm.orig 2003-06-03 16:11:07.000000000 +1000
+++ Apache2/compat.pm 2003-06-03 16:11:58.000000000 +1000
@@ -1,5 +1,9 @@
package Apache2::compat;

+BEGIN {
+ use Carp;
+ Carp::cluck("Apache2::compat is loaded by");
+}

I've used this last technique, since it's the safest one to use. Remember that Apache2::compat can also be loaded with:

私はこれが使える中で最も安全なので, 最後のテクニックを使いました。Apache2::compat は次のものでもロードできることを覚えておいてください:

do "Apache2/compat.pm";

in which case, neither grep(1)'ping for Apache2::compat, nor overriding require() will do the job.

このケースでは, Apache2::compat のための grep(1) での出力も, require() の上書きもどちらも仕事をしません。
When I've restarted the server and tried to use Apache::MP3 (I wasn't preloading it at the server startup since I wanted the server to start normally and cope with problem when it's running), the error_log had an entry:

私がサーバをリスタートして Apache::MP3 の仕様を試みたとき (私は サーバを普通にスタートしてそれが走ったときにうまく対処したかったので私はそれをサーバ startup でプレロードしていません), error_log はこのエントリをもちました:

Apache2::compat is loaded by at .../Apache2/compat.pm line 6
Apache2::compat::BEGIN() called at .../Apache2/compat.pm line 8
eval {...} called at .../Apache2/compat.pm line 8
require Apache2/compat.pm called at .../5.9.0/CGI.pm line 169
require CGI.pm called at .../site_perl/5.9.0/Apache/MP3.pm line 8
Apache::MP3::BEGIN() called at .../Apache2/compat.pm line 8

(I've trimmed the whole paths of the libraries and the trace itself, to make it easier to understand.)

(理解を簡単にするために, ライブラリのパス全体とトレースそれ自身を私はトリミングしました。)
We could have used Carp::carp() which would have told us only the fact that Apache2::compat was loaded by CGI.pm, but by using Carp::cluck() we've obtained the whole stack backtrace so we also can learn which module has loaded CGI.pm.

私たちは Cparp::carp() を使って Apache2::compat が CGI.pm によってロードされている事実だけを私たちに伝えるようにできますが, Carp::cluck() を使うことで私たちはスタック全体のバックトレースを取得してあるので私たちはどのモジュールが CGI.pm をロードしていたかも知ることができます。
Here I've learned that I had an old version of CGI.pm (2.89) which automatically loaded Apache2::compat (which should be never done by CPAN modules). Once I've upgraded CGI.pm to version 2.93 and restarted the server, Apache2::compat wasn't getting loaded any longer.

ここで私は私が CGI.pm の古いバージョン (2.89) をもっていてそれが自動的に Apache2::compat をロードしていたこと (これは CPAN モジュールで決してやってはいけません) を学びました。私は CGI.pm をバージョン 2.93 にアップグレードしてサーバをリスタートしたら, Apache2::compat はもうロードされなくなりました。


ModPerl::MethodLookup ヘルパをインストールする : Installing the ModPerl::MethodLookup Helper


Now that Apache2::compat is not loaded, I need to deal with two issues: modules that need to be loaded and APIs that have changed.

いま Apache2::compat はロードされていないので, 私は 2 つの問題に対処する必要があります: 読み込む必要のあるモジュールと変更された API です。
For the second issue I'll have to refer to the the mod_perl 1.0 backward compatibility document.

2 番目の問題で私は the mod_perl 1.0 backward compatibility document を参照しなければなりません。
But the first issue can be easily worked out using ModPerl::MethodLookup. As explained in the section Using ModPerl::MethodLookup Programmatically I've added the AUTOLOAD code to my startup.pl so it'll automatically lookup the packages that I need to load based on the request method and the object type.

しかし最初の問題は ModPerl::MethodLookup を使って簡単に解決できます。セクション Using ModPerl::MethodLookup Programmatically で説明されているように私は私の startup.pl に AUTOLOAD コードを追加したので私がリクエストメソッドとオブジェクトタイプに基づいてロードを必要とするパッケージを自動的に探します。
So now my startup.pl looked like:

ですから私の startup.pl はいまこのようになります:

#file:startup.pl
#---------------
use lib qw(/home/httpd/2.0/perl);

{
package ModPerl::MethodLookupAuto;
use ModPerl::MethodLookup;

use Carp;
sub handler {

# look inside mod_perl:: Apache2:: APR:: ModPerl:: excluding DESTROY
# DESTROY を除外して mod::perl Apache2:: APR:: ModPerl:: の内側をみる
my $skip = '^(?!DESTROY$';
*UNIVERSAL::AUTOLOAD = sub {
my $method = $AUTOLOAD;
return if $method =~ /DESTROY/;
my ($hint, @modules) =
ModPerl::MethodLookup::lookup_method($method, @_);
$hint ||= "Can't find method $AUTOLOAD";
croak $hint;
};
return 0;
}
}
1;

and I add to my httpd.conf:

それと私は私の httpd.conf にこれを追加します:

PerlChildInitHandler ModPerl::MethodLookupAuto



mod_perl 2 のもとで実行するためにコードを調整する : Adjusting the code to run under mod_perl 2


I restart the server and off I go to complete the second porting stage.

私はサーバをリスタートして 2 番目の移植ステージを完了させにいきます。
The first error that I've received was:

私が受けとった最初のエラーはこれです:

[Fri Jun 06 16:28:32 2003] [error] failed to resolve handler `Apache::MP3'
[Fri Jun 06 16:28:32 2003] [error] [client 127.0.0.1] Can't locate
object method "boot" via package "mod_perl" at .../Apache/Constants.pm
line 8. Compilation failed in require at .../Apache/MP3.pm line 12.

I go to line 12 and find the following code:

私は 12 行目にいき次のコードを見つけます:

use Apache::Constants qw(:common REDIRECT HTTP_NO_CONTENT
DIR_MAGIC_TYPE HTTP_NOT_MODIFIED);

Notice that I did have mod_perl 1.0 installed, so the Apache::Constant module from mod_perl 1.0 couldn't find the boot() method which doesn't exist in mod_perl 2.0. If you don't have mod_perl 1.0 installed the error would simply say, that it can't find Apache/Constants.pm in @INC. In any case, we are going to replace this code with mod_perl 2.0 equivalent:

私は mod_perl 1.0 をインストールしていたので, mod_perl 2.0 では存在しない mod_perl 1.0 からの Apache::Constant モジュールは boot() メソッドを見つけることができなかったことに注目してください。あなたが mod_perl 1.0 をインストールしていない場合エラーはシンプルに @INC で Apache/Constants.pm が見つからないと, 言います。いずれにせよ, 私たちはこのコードを 同等の mod_perl 2.0 でリプレイスします:

--- Apache/MP3.pm.6 2003-06-06 16:33:05.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 17:03:43.000000000 +1000
@@ -9,7 +9,9 @@
use warnings;
no warnings 'redefine'; # XXX: remove when done with porting

-use Apache::Constants qw(:common REDIRECT HTTP_NO_CONTENT DIR_MAGIC_TYPE HTTP_NOT_MODIFIED);
+use Apache2::Const -compile => qw(:common REDIRECT HTTP_NO_CONTENT
+ DIR_MAGIC_TYPE HTTP_NOT_MODIFIED);
+
use Apache::MP3::L10N;
use IO::File;
use Socket 'sockaddr_in';

and I also had to adjust the constants, since what used to be OK, now has to be Apache2::Const::OK, mainly because in mod_perl 2.0 there is an enormous amount of constants (coming from Apache and APR) and most of them are grouped in Apache2:: or APR:: namespaces. The Apache2::Const and APR::Const manpage provide more information on available constants.

それから以前は OK だったものが, いまは Apache2::Const::OK にしなければならなかったので, 私は定数も調整しなければなりませんでした, 主な理由は mod_perl 2.0 では (Apcahe と APR からの) 膨大な量の定数がありそれらのほとんどが Apache2:: または APR:: の名前空間でグループ化されたことです。
This search and replace accomplished the job:

この検索とリプレイスは仕事を成しました:

% perl -pi -e 's/return\s(OK|DECLINED|FORBIDDEN| \
REDIRECT|HTTP_NO_CONTENT|DIR_MAGIC_TYPE| \
HTTP_NOT_MODIFIED)/return Apache2::$1/xg' Apache/MP3.pm

As you can see the regex explicitly lists all constants that were used in Apache::MP3. Your situation may vary. Here is the patch: code/apache_mp3_7.diff.

見てのとおり正規表現は Apache::MP3 で使われているすべての定数を明示的にリストしています。あなたの状況では違うかもしれません。こちらがそのパッチです: code/apache_mp3_7.diff (# diff ファイルへのダイレクトリンク # Note: This file needs to be replaced s/Apache::/Apache2::/g)
I had to manually fix the DIR_MAGIC_TYPE constant which didn't fit the regex pattern:

定数 DIR_MAGIC_TYPE が正規表現パターンにフィットしなかったので私は手動でフィックスする必要がありました:

--- Apache/MP3.pm.8 2003-06-06 17:24:33.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 17:26:29.000000000 +1000
@@ -1055,7 +1055,7 @@

my $mime = $self->r->lookup_file("$dir/$d")->content_type;

- push(@directories,$d) if !$seen{$d}++ && $mime eq DIR_MAGIC_TYPE;
+ push(@directories,$d) if !$seen{$d}++ && $mime eq Apache2::Const::DIR_MAGIC_TYPE;

# .m3u files should be configured as audio/playlist MIME types in your apache .conf file
push(@playlists,$d) if $mime =~ m!^audio/(playlist|x-mpegurl|mpegurl|x-scpls)$!;

And I move on, the next error is:

そして私は進みます, 次のエラーは:

[Fri Jun 06 17:28:00 2003] [error] [client 127.0.0.1]
Can't locate object method "header_in" via package
"Apache2::RequestRec" at .../Apache2/MP3.pm line 85.

The porting document quickly reveals me that header_in() and its brothers header_out() and err_header_out() are R.I.P. and that I have to use the corresponding functions headers_in(), headers_out() and err_headers_out() which are available in mod_perl 1.0 API as well.

The porting document はheader_in() とその兄弟の header_out() それから err_header_out() が R.I.P であり私は mod_perl 1.0 API でも利用可能なこれに対応するファンクション headers_in(), headers_out() それから err_headers_out() を使わなけれならないことをことを私にすぐに示します。
So I adjust the code to use the new API:

ですから私は新しい API を使ってコードを調整します:

% perl -pi -e 's|header_in\((.*?)\)|headers_in->{$1}|g' Apache/MP3.pm
% perl -pi -e 's|header_out\((.*?)\s*=>\s*(.*?)\);|headers_out->{$1} = $2;|g' Apache/MP3.pm

which results in this patch: code/apache_mp3_9.diff.

その結果がこのパッチです: code/apache_mp3_9.diff (# diff ファイルへのダイレクトリンク)。
On the next error ModPerl::MethodLookup's AUTOLOAD kicks in. Instead of complaining:

次のエラーで ModPerl::MethodLookup の AUTOLOAD が作動します。文句を言うかわりに:

[Fri Jun 06 18:35:53 2003] [error] [client 127.0.0.1]
Can't locate object method "FETCH" via package "APR::Table"
at .../Apache/MP3.pm line 85.

I now get:

そして私はゲットします:

[Fri Jun 06 18:36:35 2003] [error] [client 127.0.0.1]
to use method 'FETCH' add:
use APR::Table ();
at .../Apache/MP3.pm line 85

So I follow the suggestion and load APR::Table():

ですから私は提案に従い APR::Table() をロードします:

--- Apache/MP3.pm.10 2003-06-06 17:57:54.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 18:37:33.000000000 +1000
@@ -9,6 +9,8 @@
use warnings;
no warnings 'redefine'; # XXX: remove when done with porting

+use APR::Table ();
+

I continue issuing the request and adding the missing modules again and again till I get no more complaints. During this process I've added the following modules:

私はリクエストの発行を続けて私が文句をいわれなくなるまで何度も見つからないモジュールを追加します。このプロセスの間で私は次のモジュールを追加しました:

--- Apache/MP3.pm.11 2003-06-06 18:38:47.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 18:39:10.000000000 +1000
@@ -9,6 +9,14 @@
use warnings;
no warnings 'redefine'; # XXX: remove when done with porting

+use Apache2::Connection ();
+use Apache2::SubRequest ();
+use Apache2::Access ();
+use Apache2::RequestIO ();
+use Apache2::RequestUtil ();
+use Apache2::RequestRec ();
+use Apache2::ServerUtil ();
+use Apache2::Log;
use APR::Table ();

use Apache2::Const -compile => qw(:common REDIRECT HTTP_NO_CONTENT

The AUTOLOAD code helped me to trace the modules that contain the existing APIs, however I still have to deal with APIs that no longer exist. Rightfully the helper code says that it doesn't know which module defines the method: send_http_header() because it no longer exists in Apache 2.0 vocabulary:

AUTOLOAD コードは既存の API を含むモジュールをトレースするために私を助けましたが, しかし私はまだもう存在しない API の処理をしなければなりません。当然ながらどのモジュールがこのメソッドを定義したか知らないとヘルパコードはいいます: send_http_header() なぜなら Apache 2.0 のボキャブラリにもう存在しないからです:

[Fri Jun 06 18:40:34 2003] [error] [client 127.0.0.1]
Don't know anything about method 'send_http_header'
at .../Apache/MP3.pm line 498

So I go back to the porting document and find the relevant entry. In 2.0 lingo, we just need to set the content_type():

ですから私は the porting document に戻り関連するエントリを見つけます。2.0 の用語では, 私は content_type() にセットする必要があります:

--- Apache/MP3.pm.12 2003-06-06 18:43:42.000000000 +1000
+++ Apache/MP3.pm 2003-06-06 18:51:23.000000000 +1000
@@ -138,7 +138,7 @@
sub help_screen {
my $self = shift;

- $self->r->send_http_header( $self->html_content_type );
+ $self->r->content_type( $self->html_content_type );
return Apache2::Const::OK if $self->r->header_only;

print start_html(
@@ -336,7 +336,7 @@
my $r = $self->r;
my $base = $self->stream_base;

- $r->send_http_header('audio/mpegurl');
+ $r->content_type('audio/mpegurl');
return Apache2::Const::OK if $r->header_only;

# local user
@@ -495,7 +495,7 @@
return Apache2::Const::DECLINED unless my ($directories,$mp3s,$playlists,$txtfiles)
= $self->read_directory($dir);

- $self->r->send_http_header( $self->html_content_type );
+ $self->r->content_type( $self->html_content_type );
return Apache2::Const::OK if $self->r->header_only;

$self->page_top($dir);

also I've noticed that there was this code:

また私はこのコードがあることに気づきました:

return Apache2::Const::OK if $self->r->header_only;

This technique is no longer needed in 2.0, since Apache 2.0 automatically discards the body if the request is of type HEAD -- the handler should still deliver the whole body, which helps to calculate the content-length if this is relevant to play nicer with proxies. So you may decide not to make a special case for HEAD requests.

Apache 2.0 はリクエストが HEAD タイプの場合ボディを自動的に破棄するので, このテクニックは 2.0 ではもう必要とされていません -- ハンドラはいまだボディ全体を配送します, これはそれがプロキシでよりナイスにプレイすることに関連している場合に content-lenght を計算することを助けます。ですからあなたは HEAD リクエストで特別なケースを作らないと決めてもよいです。
At this point I was able to browse the directories and play files via most options without relying on Apache2::compat.

この時点で私は Apache2::compat に頼ることなくほとんどのオプションを介してディレクトリのブラウズとファイルのプレイができるようになりました。
There were a few other APIs that I had to fix in the same way, while trying to use the application, looking at the error_log referring to the porting document and applying the suggested fixes. I'll make sure to send all these fixes to Lincoln Stein, so the new versions will work correctly with mod_perl 2.0. I also had to fix other Apache::MP3:: files, which come as a part of the Apache-MP3 distribution, pretty much using the same techniques explained here. A few extra fixes of interest in Apache::MP3 were:

このアプリケーションの利用をトライしている間で, error_log を確認して the porting document を参照しつつ提案されたフィックスを適用するという同じ方法で, 私がフィックスしなければならない他の API がいくつかありました。
私は Lincoln Stein にこれらのフィックスすべてを必ず送るので, この新しいバージョンが mod_perl 2.0 で正しく動作するようにします。また私は他の Apache::MP3:: ファイルをフィックスしなければなりませんでした, それは Apache-MP3 ディストリビューションの一部となるもので, 概ねここで説明されたのと同じテクニックを使っています。Apache::MP3 での興味深いいくつかの追加のフィックスはこれです:

  • send_fd()
    As of this writing we don't have this function in the core, because Apache 2.0 doesn't have it (it's in Apache2::compat but implemented in a slow way). However we may provide one in the future. Currently one can use the function sendfile() which requires a filename as an argument and not the file descriptor. So I have fixed the code:

    これを書いている時点で Apache 2.0 はそれを持っていないので (これは Apache2::compat にありますが遅い実装です), 私たちはこのファンクションをコアに持っていません。しかし私たちはこれを将来的に提供するかもしれません。現在これは引数としてファイルディスクリプタではなくファイル名を必要とするファンクション sendfile() を使えます。ですから私はコードをこのようにフィックスしました:

    - if($r->request($r->uri)->content_type eq 'audio/x-scpls'){
    - open(FILE,$r->filename) || return 404;
    - $r->send_fd(\*FILE);
    - close(FILE);
    +
    + if($r->content_type eq 'audio/x-scpls'){
    + $r->sendfile($r->filename) || return Apache2::Const::NOT_FOUND;


  • log_reason
    log_reason is now log_error:

    log_reason はいま log_error です:

    - $self->r->log_reason('Invalid parameters -- possible attempt to circumvent checks.');
    + $r->log_error('Invalid parameters -- possible attempt to circumvent checks.');



I have found the porting process to be quite interesting, especially since I have found several bugs in Apache 2.0 and documented a few undocumented API changes. It was also fun, because I've got to listen to mp3 files when I did things right, and was getting silence in my headphones and a visual irritation in the form of error_log messages when I didn't ;)

私はこの移植プロセスがかなり興味深いことになることがわかりました, 特に私は Apache 2.0 でいくつかのバグを見つけたうえドキュメント化されていない幾ばくかの API の変更をドキュメント化したからです。
私は私が正しいことをしたときに mp3 ファイルを効かなければならず, また私がそうでないときは私のヘッドフォンで沈黙を error_log メッセージの形でビジュアルの刺激を受けたので, それはそれで楽しかったです ;)


mod_per 1.0 と 2.0 の両方で実行するためにモジュールを移植する : Porting a Module to Run under both mod_perl 2.0 and mod_perl 1.0


Sometimes code needs to work with both mod_perl versions. For example this is the case with CPAN module developers who wish to continue to maintain a single code base, rather than supplying two separate implementations.

コードはときおり両方の mod_perl バージョンで機能することを必要とします。例えばこれは2 つに分けた実装ではなく単一のコードベースでのメンテを継続したいと望む CPAN モジュール開発者のケースです。


mod_perl Version の実行でコードを条件付きにする : Making Code Conditional on Running mod_perl Version


In this case you can test for which version of mod_perl your code is running under and act appropriately.

このケースではどの mod_perl のバージョンのもとであなたのコードが走っているかをあなたがテストできて適切に動作させられます。
To continue our example above, let's say we want to support opening a filehandle in both mod_perl 2.0 and mod_perl 1.0. Our code can make use of the environment variable $ENV{MOD_PERL_API_VERSION}

上記の例を継続するために, 私たちが mod_perl 2.0 と mod_perl 1.0 の両方でファイルハンドルのオープンをサポートしたいということにしましょう。私たちのコードは 環境変数 $ENV{MOD_PERL_API_VERSION} を使えるようにします。

use mod_perl;
use constant MP2 => ( exists $ENV{MOD_PERL_API_VERSION} and
$ENV{MOD_PERL_API_VERSION} >= 2 );
# ...
require Symbol if MP2;
# ...

my $fh = MP2 ? Symbol::gensym : Apache->gensym;
open $fh, $file or die "Can't open $file: $!";

Some modules, like CGI.pm may work under mod_perl and without it, and will want to use the mod_perl 1.0 API if that's available, or mod_perl 2.0 API otherwise. So the following idiom could be used for this purpose.

CGI.pm のような, いくつかのモジュールはそれがなくても mod_perl のもとで動くかもしれず, もし mod_perl 1.0 API が利用可能なら使い, そうでなければ mod_perl 2.0 API を使うはずです。ですから次のイディオムをこの目的に使うことができます。

use constant MP_GEN => $ENV{MOD_PERL}
? { ( exists $ENV{MOD_PERL_API_VERSION} and
$ENV{MOD_PERL_API_VERSION >= 2 ) ? 2 : 1 }
: 0;

It sets the constant MP_GEN to 0 if mod_perl is not available, to 1 if running under mod_perl 1.0 and 2 for mod_perl 2.0.

これは定数 MP_GEN を mod_perl が利用できない場合は 0 , mod_perl 1.0 の下で走っている場合は 1 それから mod_perl 2.0 では 2 にセットします。
Here's another way to find out the mod_perl version. In the server configuration file you can use a special configuration "define" symbol MODPERL2, which is magically enabled internally, as if the server had been started with -DMODPERL2.

こちらは mod_perl のバージョンを見つけだす別の方法です。サーバ構成ファイルであなたは特別な構成 "define" シンボル MODPEL2 を使用でき, これはサーバが -DMODPERL2 でスタートされたかのように, 内部的にマジカルに有効化されます,

# in httpd.conf
<IfDefine MODPERL2>
# 2.0 configuration
</IfDefine>
<IfDefine !MODPERL2>
# else
</IfDefine>

From within Perl code this can be tested with Apache2::exists_config_define(). For example, we can use this method to decide whether or not to call $r->send_http_header(), which no longer exists in mod_perl 2.0:

Perl コードの中から Apache2::exists_config_define() でテストさせることができます。例えば, 私たちは mod_perl 2.0 ではもう存在しない, $r->send_http_header() をコールするかどうかを決定するためにこのメソッドを使います:

sub handler {
my $r = shift;
$r->content_type('text/html');
$r->send_http_header() unless Apache2::exists_config_define("MODPERL2");
...
}

Relevant links to other places in the porting documents:

関連数移植ドキュメントの他の場所へのリンク:



メソッドハンドラ : Method Handlers


Method handlers in mod_perl are declared using the 'method' attribute. However if you want to have the same code base for mod_perl 1.0 and 2.0 applications, whose handler has to be a method, you will need to do the following trick:

mod_perl のメソッドハンドラは 'method' アトリビュートを使って宣言されます。しかしあなたがハンドラがメソッドでなければならない, mod_perl 1.0 と 2.0 のアプリケーションで同じコードベースを持ちたいなら, あなたは次のトリックを行う必要があります:

sub handler_mp1 ($$) { ... }
sub handler_mp2 : method { ... }
*handler = MP2 ? \&handler_mp2 : \&handler_mp1;

Note that this requires at least Perl 5.6.0, the :method attribute is not supported by older Perl versions, which will fail to compile such code.

これは少なくとも Perl 5.6.0 を要求することに注意して下さい, :method アトリビュートは古い Perl バージョンではサポートされていないので, このようのコードはコンパイルに失敗します。
Here are two complete examples. The first example implements MyApache2::Method which has a single method that works for both mod_perl generations:

こちらは 2 つの完全な例です。最初の例は両方の mod_perl ジェネレーションで機能する単一のメソッドをもつ MyApache2::Method を実装します:
The configuration:

その構成:

PerlModule MyApache2::Method
<Location /method>
SetHandler perl-script
PerlHandler MyApache2::Method->handler
</Location>

The code:

そのコード:

#file:MyApache2/Method.pm
package MyApache2::Method;

# PerlModule MyApache2::Method
# <Location /method>
# SetHandler perl-script
# PerlHandler MyApache2::Method->handler
# </Location>

use strict;
use warnings;

use mod_perl;
use constant MP2 => ( exists $ENV{MOD_PERL_API_VERSION } and
$ENV{MOD_PERL_API_VERSION >=2 );

BEGIN {
if (MP2) {
require Apache2::RequestRec;
require Apache2::RequestIO;
require Apache2::Const;
Apache2::Const->import(-compile => 'OK');
}
else {
require Apache;
require Apache::Constants;
Apache::Constants->import('OK');
}
}

sub handler_mp1 ($$) { &run }
sub handler_mp2 : method { &run }
*handler = MP2 ? \&handler_mp2 : \&handler_mp1;

sub run {
my ($class, $r) = @_;
MP2 ? $r->content_type ('text/plain')
: $r->send_http_header('text/plain');
print "$class was called\n";
return MP2 ? Apache2::Const::OK : Apache::Constants::OK;
}

Here are two complete examples. The second example implements MyApache2::Method2, which is very similar to MyApache2::Method, but uses separate methods for mod_perl 1.0 and 2.0 servers.

こちらが 2 つの完全な例です。2 番目の例は MyApache2::Method2 を実装します, これは MyApache2::Method ととても似ていますが, mod_perl 1.0 と 2.0 サーバのために別のメソッドを使います。
The configuration is the same:

その構成は同じ:

PerlModule MyApache2::Method2
<Location /method2>
SetHandler perl-script
PerlHandler MyApache2::Method2->handler
</Location>

The code:

そのコード:

#file:MyApache2/Method2.pm
package MyApache2::Method2;

# PerlModule MyApache2::Method2
# <Location /method2>
# SetHandler perl-script
# PerlHandler MyApache2::Method2->handler
# </Location>

use strict;
use warnings;

use mod_perl;
use constant MP2 => ( exist $ENV{MOD_PERL_API_VERSION} and
$ENV{MOD_PERL_API_VERSION >=2 );

BEGIN {
warn "running $ENV{MOD_PERL_API_VERSION}\n";
if (MP2) {
require Apache2::RequestRec;
require Apache2::RequestIO;
require Apache2::Const;
Apache2::Const->import(-compile => 'OK');
}
else {
require Apache;
require Apache::Constants;
Apache::Constants->import('OK');
}
}

sub handler_mp1 ($$) { &mp1 }
sub handler_mp2 : method { &mp2 }

*handler = MP2 ? \&handler_mp2 : \&handler_mp1;

sub mp1 {
my ($class, $r) = @_;
$r->send_http_header('text/plain');
$r->print("mp1: $class was called\n";
retunr Apache::Constants::OK();
}

sub mp2 {
my ($class, $r) = @_;
$r->content_type('text/plain');
$r->print("mp2: $class was called\n");
return Apache2::Const::OK();
}

Assuming that mod_perl 1.0 is listening on port 8001 and mod_perl 2.0 on 8002, we get the following results:

mod_perl 1.0 がポート 8001 を mod_perl 2.0 がポート 8002 をリッスンしていると想定すると, 私たちは次の結果を得ます:

% lynx --source http://localhost:8001/method
MyApache2::Method was called

% lynx --source http://localhost:8001/method2
mp1: MyApache2::Method2 was called

% lynx --source http://localhost:8002/method
MyApache2::Method was called

% lynx --source http://localhost:8002/method2
mp2: MyApache2::Method2 was called



mp1 vs mp2 ... vs mpNN の競合 : The Conflict of mp1 vs mp2 vs mp22 vs ... vs mpNN


META: should something be said here?

META: ここで何かいうべき ?


ディストリビュータ : Distributors


Distributors should mark the different generations of mod_perl core as conflicting, so only one version can be installed using the binary package. Users requiring more than one installation should do a manual install.

ディストリビュータは mod_perl コアの異なるジェネレーションを衝突するものとしてマークしなければなりませんので, インストールして使えるバイナリパッケージは 1 つのバージョンのみです。複数のインストールを必要とするユーザは手動でインストールを行います。
In order to have any of the 3rd party modperl modules installed users need to have the correct modperl package installed. So there is no need to mark the 3rd party modules as conflicting, since their most important prerequisite (the modperl-core) is already handling that.

いずれかの 3rd パーティの modperl モジュールをインストールするためにユーザは正しい modperl パッケージをインストールする必要があります。ですから 3rd パーティモジュールは衝突する物としてマークする必要はありません, もっとも重要な prerequisite (# 前提条件) (the modperl-core) がすでにそれを処理しているからです。
Of course packagers can decide to make the two generation packages as non-conflicting, by building all mp2 core and 3rd party modules into Apache2/ subdir, in which case the two will always co-exist. But this is not the most logical approach since 99% of users will want only one generation of mod_perl core and 3rd party modules.

もちろんパッケージャはすべての mp2 コアと 3rd パーティモジュールを Apache2/ サブディレクトリの中にビルドすることで, 2 つのジェネレーションを衝突しないものにでき, この場合その 2 つは常に共存します。しかしユーザの 99% は mod_perl の 1 つのジェネレーションと 3rd パーティモジュールを望むはずなのでこれはもっとも非論理的なアプローチです。


メンテナ : Maintainers


Maintainer is the person(s) you should contact with updates, corrections and patches.
  • Stas Bekman [http://stason.org/]



作者 : Authors



  • Nick Tonkin

  • Stas Bekman [http://stason.org/]


Only the major authors are listed above. For contributors see the Changes file.


NEXT



次回は、「 A Reference to mod_perl 1.0 to mod_perl 2.0 Migration 」を「 mod_perl 」公式サイト (https://perl.apache.org/index.html) より確認します。


参考情報は書籍「 続・初めての Perl 改訂版 」, 「 Effective Perl 第 2 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。

目次 - Perl Index











































同じカテゴリー(Perl)の記事
 Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228) (2023-10-11 23:49)
 Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227) (2023-05-26 15:41)
 Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226) (2023-05-19 17:05)
 Perl mp2 翻訳 テンプレートシステムの選択 (d225) (2022-08-15 22:23)
 Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224) (2022-06-15 20:43)
 Perl mp2 翻訳 チュートリアル (d223) (2022-06-15 20:42)
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

Llama
リャマ
TI-DA
てぃーだブログ
プロフィール
セラ (perlackline)
セラ (perlackline)
QRコード
QRCODE
オーナーへメッセージ

PAGE TOP ▲