perl-modperl-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject cvs commit: modperl-docs/src/docs/2.0/user/porting porting.pod compat.pod
Date Fri, 11 Apr 2003 03:20:09 GMT
stas        2003/04/10 20:20:09

  Modified:    src/docs/2.0/api/Apache compat.pod
               src/docs/2.0/devel/porting porting.pod
               src/docs/2.0/user config.cfg
               src/docs/2.0/user/porting compat.pod
  Added:       src/docs/2.0/user/porting porting.pod
  Log:
  split the porting doc in two parts, moving the perl code porting to the
  user "folder", adjust links
  
  Revision  Changes    Path
  1.4       +3 -2      modperl-docs/src/docs/2.0/api/Apache/compat.pod
  
  Index: compat.pod
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/2.0/api/Apache/compat.pod,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- compat.pod	11 Apr 2003 02:24:36 -0000	1.3
  +++ compat.pod	11 Apr 2003 03:20:08 -0000	1.4
  @@ -27,7 +27,7 @@
   However, remember, that it's implemented in pure Perl and not C,
   therefore its functionality is not optimized and it's the best to try
   to L<port your
  -code|docs::2.0::devel::porting::porting> not to use deprecated
  +code|docs::2.0::user::porting::porting> not to use deprecated
   functions and stop using the compatibility layer.
   
   =head1 Use in CPAN Modules
  @@ -50,7 +50,8 @@
   be enforced by CPAN modules.
   
   If you port your CPAN modules to work with mod_perl 2.0, you should
  -follow the L<porting guidelines|docs::2.0::devel::porting::porting>.
  +follow the porting L<Perl|docs::2.0::user::porting::porting> and
  +L<XS|docs::2.0::devel::porting::porting> module guidelines.
   
   Users that are stuck with CPAN modules preloading C<Apache::compat>,
   can prevent this from happening by adding
  
  
  
  1.13      +10 -481   modperl-docs/src/docs/2.0/devel/porting/porting.pod
  
  Index: porting.pod
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/2.0/devel/porting/porting.pod,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- porting.pod	11 Apr 2003 02:24:36 -0000	1.12
  +++ porting.pod	11 Apr 2003 03:20:09 -0000	1.13
  @@ -1,484 +1,23 @@
   =head1 NAME
   
  -Porting Apache:: Modules from mod_perl 1.0 to 2.0
  +Porting Apache:: XS Modules from mod_perl 1.0 to 2.0
   
   =head1 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.
  -
  -=head1 Introduction
  -
  -In the vast majority of cases, a perl Apache module that runs under
  -mod_perl 1.0 will B<not> run under mod_perl 2.0 without at least some
  -degree of modification.
  -
  -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.
  +This document talks mainly about porting modules using XS code. It's
  +also helpful to those who start developing mod_perl 2.0 packages.
   
  -Most real-life modules will in fact need to deal with the following
  -changes:
  +Also make sure to first read about L<porting Apache:: Perl
  +modules|src::docs::2.0::user::porting::porting>.
   
  -=over
  -
  -=item *
  -
  -methods that have moved to a different (new) package
  -
  -=item *
  -
  -methods that must be called differently (due to changed prototypes)
  -
  -=item *
  -
  -methods that have ceased to exist (functionality provided in some
  -other way)
  -
  -=back
  -
  -B<Do not be alarmed!> One way to deal with all of these issues is to
  -load the C<L<Apache::compat|docs::2.0::api::Apache::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.
  -
  -There are three basic options for porting. Let's take a quick look at
  -each one and then discuss each in more detail.
  -
  -=over
  -
  -=item 1 Run the module on 2.0 under C<Apache::compat> with no further changes
  -
  -As we have said mod_perl 2.0 ships with a module,
  -C<L<Apache::compat|docs::2.0::api::Apache::compat>>, that provides a
  -complete drop-in compatibility layer for 1.0
  -modules. C<Apache::compat> does the following:
  -
  -=over
  -
  -=item *
  -
  -Loads all the mod_perl 2.0 Apache:: modules
  -
  -=item *
  -
  -Adjusts method calls where the prototype has changed
  -
  -=item *
  -
  -Provides Perl implementation for methods that no longer exist in 2.0
  -
  -=back
  -
  -The drawback to using C<Apache::compat> is the performance hit, which
  -can be significant.
  -
  -Authors of CPAN and other publicly distributed modules should not use
  -C<Apache::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.
  -
  -=item 2 Modify the module to run only under 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.
  -
  -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.
  -
  -=item 3 Modify the module so that it runs under both 1.0 and 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.
  -
  -This is a relatively simple ehancement of option (2) above. The module
  -tests to see which version of mod_perl is in use and then executes the
  -appropriate method call.
  -
  -=back
  -
  -The following sections provide more detailed information and
  -instructions for each of these three porting strategies.
  -
  -=head1 Using the C<Apache::compat> Layer
  -
  -The C<L<Apache::compat|docs::2.0::api::Apache::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.
  -
  -C<Apache::compat> is extremely easy to use. Either add at the very
  -beginning of startup.pl:
  -
  -  use Apache2;
  -  use Apache::compat;
  -
  -or add to httpd.conf:
  -
  -  PerlModule Apache2
  -  PerlModule Apache::compat
  -
  -That's all there is to it. Now you can run your 1.0 module unchanged.
  -
  -Remember, however, that using C<Apache::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.
  -
  -It's also especially important to repeat that C<L<CPAN module
  -developers are requested not to use this module in their
  -code|docs::2.0::api::Apache::compat/Use_in_CPAN_Modules>>, since this
  -takes the control over performance away from users.
  -
  -=head1 Porting a Perl Module to Run under mod_perl 2.0
  -
  -Note: API changes are listed in L<the backwards compatibility
  -document|docs::2.0::user::porting::compat/>.
  -
  -The following sections will guide you through the steps of porting
  -your modules to mod_perl 2.0.
  -
  -=head2 Using C<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.
  -
  -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 C<use()> them.
  -
  -The L<MethodLookup module|docs::2.0::api::ModPerl::MethodLookup>
  -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.
  -
  -For example, let's say we have a mod_perl 1.0 code snippet:
  -
  -  $r->content_type('text/plain');
  -  $r->print("Hello cruel world!");
  -
  -If we run this, mod_perl 2.0 will complain that the method
  -C<content_type()> can't be found. So we use C<ModPerl::MethodLookup>
  -to figure out which module provides this method. We can just run this
  -from the command line:
  -
  -  % perl -MApache2 -MModPerl::MethodLookup -le \
  -    'print((ModPerl::MethodLookup::lookup_method(shift))[0])' \
  -    content_type
  -
  -This prints:
  -
  -  to use method 'content_type' add:
  -           use Apache::RequestRec ();
  -
  -We do what it says and add this C<use()> statement to our code,
  -restart our server (unless we're using
  -C<L<Apache::Reload|docs::2.0::api::Apache::Reload>>), and mod_perl
  -will no longer complain about this particular method.
  -
  -Since you may need to use this technique quite often you may want to
  -C<L<define an
  -alias|docs::2.0::api::ModPerl::MethodLookup/Command_Line_Lookups>>. Once 
  -defined the last command line lookup can be accomplished with:
  -
  -  % lookup content_type
  -
  -=head3 Handling Methods Existing In More Than One Package
  -
  -Some methods exists in several classes. For example this is the case
  -with the C<print()> method. We know the drill:
  -
  -  % lookup print
  -
  -This prints:
  -
  -  There is more than one class with method 'print'
  -  try one of:
  -        use Apache::RequestIO ();
  -        use Apache::Filter ();
  -
  -So there is more than one package that has this method. Since we know
  -that we call the C<print()> method with the C<$r> object, it must be
  -the C<Apache::RequestIO> module that we are after. Indeed, loading
  -this module solves the problem.
  -
  -=head3 Using C<ModPerl::MethodLookup> Programmatically
  -
  -The issue of picking the right module, when more than one matches, can
  -be resolved when using C<ModPerl::MethodLookup> programmatically --
  -C<L<lookup_method|docs::2.0::api::ModPerl::MethodLookup/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. C<ModPerl::MethodLookup> knows that C<Apache::RequestIO> and
  -and C<Apache::Filter> expect an object of type C<Apache::RequestRec>
  -and type C<Apache::Filter> respectively. So in a program running under
  -mod_perl we can call:
  -
  -  ModPerl::MethodLookup::lookup_method('print', $r);
  +=head1 Porting Makefile.PL
   
  -Now only one module will be matched.
  +It's only an issue if it was using C<Apache::src>. A new configuration
  +system is in works. So watch this space for updates on this issue.
   
  -This functionality can be used in
  -C<L<AUTOLOAD|docs::2.0::api::ModPerl::MethodLookup/AUTOLOAD>>, for
  -example, although most users will not have a need for this robust of
  -solution.
  +ModPerl::MM is the new replacement of Apache::src.
   
  -=head3 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
  -C<L<preload_all_modules()|docs::2.0::api::ModPerl::MethodLookup/preload_all_modules__>>
  -to be the right tool for you. This function preloads B<all> mod_perl
  -2.0 modules, implementing their API in 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 B<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.
  -
  -=head2 Handling Missing and Modified mod_perl 1.0 Methods and Functions
  -
  -The mod_perl 2.0 API is modelled 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.
  -
  -If mod_perl 2.0 tells you that some method is missing and it can't be
  -found using
  -L<ModPerl::MethodLookup|/Using_ModPerl::MethodLookup_to_Discover_Which_mod_perl_2.0_Modules_Need_to_Be_Loaded>,
  -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 ditfferent arguments, etc.).
  -
  -In either of these cases, refer to L<the backwards compatibility
  -document|docs::2.0::user::porting::compat/> for an exhaustive list of
  -API calls that have been modified or removed.
  -
  -=head3 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:
  -
  -  $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 C<log_reason()>. But when we use C<ModPerl::MethodLookup> to see
  -which module to load in order to call that method, nothing is found:
  -
  -  % perl -MApache2 -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 L<the backwards compatibility
  -document|docs::2.0::user::porting::compat/>, wherein we find that as we
  -suspected, the method C<log_reason()> no longer exists, and that
  -L<instead we should use the other standard logging
  -functions|docs::2.0::user::porting::compat/C__r_E_gt_log_reason_>
  -provided by the C<Apache::Log> module.
  -
  -=head3 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:
  -
  -  $parsed_uri = Apache::URI->parse($r, $r->uri);
  -
  -This code causes mod_perl 2.0 to complain first about not being able
  -to load the method C<parse()> via the package Apache::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 C<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 C<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:
  -
  -  $parsed_uri = APR::URI->parse($r->pool, $r->uri);
  -
  -and all is well in the world again.
  -
  -=head2 Requiring a specific mod_perl version.
  -
  -To require a module to run only under 2.0, simply add:
  -
  -  use Apache2;
  -  use mod_perl 2.0;
  -
  -META: In fact, before 2.0 is released you really have to say:
  -
  -  use Apache2;
  -  use mod_perl 1.99;
  -
  -=head2 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.
  -
  -Let's say that you have a module C<Apache::Friendly> whose release
  -version compliant with mod_perl 1.0 is 1.57. You keep this version on
  -CPAN and release a new version, 2.01, which is compliant with mod_perl
  -2.0 and preserves the name of the module. It's possible that a user
  -may need to have both versions of the module on the same
  -machine. Since the two have the same name they obviously cannot live
  -under the same tree.
  -
  -One attempt to solve this problem is to use I<Makefile.PL>'s
  -C<MP_INST_APACHE2> option. If the module is configured as:
  -
  -  % perl Makefile.PL MP_INST_APACHE2=1
  -
  -it'll be installed relative to the I<Apache2/> directory.
  -
  -META: but of course this won't work in non-core mod_perl, since a
  -generic C<Makefile.PL> has no idea what to do about
  -C<MP_INST_APACHE2=1>. Need to provide copy-n-paste recipe for this. Or
  -even add to the core a supporting module that will handle this
  -functionality.
  -
  -The second step is to change the documentation of your 2.0 compliant
  -module to instruct users to C<use Apache2 ();> in their code (or in
  -I<startup.pl> or via C<PerlModule Apache2> in I<httpd.conf>) before
  -the module is required. This will cause C<@INC> to be modified to
  -include the I<Apache2/> directory first.
  -
  -The introduction of the I<Apache2/> directory is similar to how Perl
  -installs its modules in a version specific directory. For example:
  -
  -  lib/5.7.1
  -  lib/5.7.2
  -
  -
  -=head2 Using C<Apache::compat> As a Tutorial
  -
  -Even if you have followed the recommendation and eschewed use of the
  -C<L<Apache::compat|docs::2.0::api::Apache::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 C<Apache::compt> source code and see
  -how the functionality should be implemented in mod_perl 2.0.
  -
  -For example, mod_perl 2.0 doesn't provide the C<Apache-E<gt>gensym>
  -method. As we can see if we look at the C<Apache/compat.pm> source,
  -the functionality is now available via the core Perl module C<Symbol>
  -and its C<gensym()> function. (Since mod_perl 2.0 works only with Perl
  -versions 5.6 and higher, and C<Symbol.pm> is included in the core Perl
  -distribution since version 5.6.0, there was no reason to keep
  -providing C<Apache-E<gt>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:
  -
  -  my $fh = Symbol::gensym;
  -  open $fh, $file or die "Can't open $file: $!";
  -
  -Or we can even skip loading C<Symbol.pm>, since under Perl version 5.6
  -and higher we can just do:
  -
  -  open my $fh, $file or die "Can't open $file: $!";
  -
  -=head1 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. This is the
  -case for writers of publically available and CPAN modules who wish to
  -continue to maintain a single code base, rather than supplying two
  -separate implementations.
  -
  -=head2 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.
  -
  -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 variable C<$mod_perl::VERSION>:
  -
  -  use mod_perl;
  -  use constant MP2 => ($mod_perl::VERSION >= 1.99);
  -  # ...
  -  require Symbol if MP2;
  -  # ...
  -  
  -  my $fh = MP2 ? Symbol::gensym : Apache->gensym;
  -  open $fh, $file or die "Can't open $file: $!";
  -
  -Here's another way to find out the mod_perl version. In the server
  -configuration file you can use a special configuration "define" symbol
  -C<MODPERL2>, which is magically enabled internally, as if the server
  -had been started with C<-DMODPERL2>.
  -
  -  # in httpd.conf
  -  <IfDefine MODPERL2>
  -      # 2.0 configuration
  -  </IfDefine>
  -  <IfDefine !MODPERL2>
  -      # else
  -  </IfDefine>
  -
  -From within Perl code this can be tested with
  -C<Apache::exists_config_define()>. For example, we can use this method
  -to decide whether or not to call C<$r-E<gt>send_http_header()>, which
  -no longer exists in mod_perl 2.0:
  -
  -  sub handler {
  -      my $r = shift;
  -      $r->content_type('text/html');
  -      $r->send_http_header() unless Apache::exists_config_define("MODPERL2");
  -      ...
  -  }
  -
  -
  -=head1 Porting XS Code and Makefile.PL
  +=head1 Porting XS Code
   
   If your module's XS code relies on the Apache and mod_perl C APIs,
   it's very likely that you will have to adjust the XS code to the
  @@ -499,12 +38,6 @@
   The C<20020329.1> is the value of the magic version number matching
   Apache 2.0.36, the earliest Apache version supported by mod_perl 2.0.
   
  -As for porting I<Makefile.PL>, it's only an issue if it was using
  -C<Apache::src>. A new configuration system is in works. So watch this
  -space for updates on this issue.
  -
  -META: ModPerl::MM is a likely candidate for the new replacement of Apache::src
  -
   =head1 Thread Safety
   
   META: to be written
  @@ -590,10 +123,6 @@
   =head1 Authors
   
   =over
  -
  -=item *
  -
  -Nick Tonkin E<lt>nick (at) tonkinresolutions.comE<gt>
   
   =item *
   
  
  
  
  1.22      +1 -0      modperl-docs/src/docs/2.0/user/config.cfg
  
  Index: config.cfg
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/config.cfg,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- config.cfg	11 Apr 2003 02:24:36 -0000	1.21
  +++ config.cfg	11 Apr 2003 03:20:09 -0000	1.22
  @@ -29,6 +29,7 @@
   
       group    => 'Porting',
       chapters => [qw(
  +        porting/porting.pod
           porting/compat.pod
       )],
   
  
  
  
  1.2       +7 -7      modperl-docs/src/docs/2.0/user/porting/compat.pod
  
  Index: compat.pod
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/porting/compat.pod,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- compat.pod	11 Apr 2003 02:24:37 -0000	1.1
  +++ compat.pod	11 Apr 2003 03:20:09 -0000	1.2
  @@ -1,11 +1,15 @@
   =head1 NAME
   
  -Migrating from mod_perl 1.0 to mod_perl 2.0
  +A Reference to mod_perl 1.0 to mod_perl 2.0 Migration.
   
   =head1 Description
   
  -This chapter explains how to port code and configuration files from
  -mod_perl 1.0 to mod_perl 2.0.
  +This chapter is a reference for porting code and configuration files
  +from mod_perl 1.0 to mod_perl 2.0.
  +
  +To learn about the porting process you should first read about
  +L<porting Perl modules|docs::2.0::user::porting::porting> (and may be
  +about L<porting XS modules|docs::2.0::devel::porting::porting>).
   
   As will be explained in details later loading C<Apache::compat> at the
   server startup, should make the code running properly under 1.0 work
  @@ -22,10 +26,6 @@
   You should be able to find the destiny of the functions that you
   cannot find any more or which behave differently now under the package
   names the functions belong in mod_perl 1.0.
  -
  -See also L<additional porting
  -notes|docs::2.0::devel::porting::porting>, mainly oriented for the 3rd
  -party module and core developers.
   
   =head1 Configuration Files Porting
   
  
  
  
  1.1                  modperl-docs/src/docs/2.0/user/porting/porting.pod
  
  Index: porting.pod
  ===================================================================
  =head1 NAME
  
  Porting Apache:: Perl Modules from mod_perl 1.0 to 2.0
  
  =head1 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 L<porting Apache:: XS
  modules|src::docs::2.0::devel::porting::porting>.
  
  =head1 Introduction
  
  In the vast majority of cases, a perl Apache module that runs under
  mod_perl 1.0 will B<not> run under mod_perl 2.0 without at least some
  degree of modification.
  
  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.
  
  Most real-life modules will in fact need to deal with the following
  changes:
  
  =over
  
  =item *
  
  methods that have moved to a different (new) package
  
  =item *
  
  methods that must be called differently (due to changed prototypes)
  
  =item *
  
  methods that have ceased to exist (functionality provided in some
  other way)
  
  =back
  
  B<Do not be alarmed!> One way to deal with all of these issues is to
  load the C<L<Apache::compat|docs::2.0::api::Apache::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.
  
  There are three basic options for porting. Let's take a quick look at
  each one and then discuss each in more detail.
  
  =over
  
  =item 1 Run the module on 2.0 under C<Apache::compat> with no further changes
  
  As we have said mod_perl 2.0 ships with a module,
  C<L<Apache::compat|docs::2.0::api::Apache::compat>>, that provides a
  complete drop-in compatibility layer for 1.0
  modules. C<Apache::compat> does the following:
  
  =over
  
  =item *
  
  Loads all the mod_perl 2.0 Apache:: modules
  
  =item *
  
  Adjusts method calls where the prototype has changed
  
  =item *
  
  Provides Perl implementation for methods that no longer exist in 2.0
  
  =back
  
  The drawback to using C<Apache::compat> is the performance hit, which
  can be significant.
  
  Authors of CPAN and other publicly distributed modules should not use
  C<Apache::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.
  
  =item 2 Modify the module to run only under 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.
  
  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.
  
  =item 3 Modify the module so that it runs under both 1.0 and 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.
  
  This is a relatively simple ehancement of option (2) above. The module
  tests to see which version of mod_perl is in use and then executes the
  appropriate method call.
  
  =back
  
  The following sections provide more detailed information and
  instructions for each of these three porting strategies.
  
  =head1 Using the C<Apache::compat> Layer
  
  The C<L<Apache::compat|docs::2.0::api::Apache::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.
  
  C<Apache::compat> is extremely easy to use. Either add at the very
  beginning of startup.pl:
  
    use Apache2;
    use Apache::compat;
  
  or add to httpd.conf:
  
    PerlModule Apache2
    PerlModule Apache::compat
  
  That's all there is to it. Now you can run your 1.0 module unchanged.
  
  Remember, however, that using C<Apache::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.
  
  It's also especially important to repeat that C<L<CPAN module
  developers are requested not to use this module in their
  code|docs::2.0::api::Apache::compat/Use_in_CPAN_Modules>>, since this
  takes the control over performance away from users.
  
  =head1 Porting a Perl Module to Run under mod_perl 2.0
  
  Note: API changes are listed in L<the backwards compatibility
  document|docs::2.0::user::porting::compat/>.
  
  The following sections will guide you through the steps of porting
  your modules to mod_perl 2.0.
  
  =head2 Using C<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.
  
  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 C<use()> them.
  
  The L<MethodLookup module|docs::2.0::api::ModPerl::MethodLookup>
  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.
  
  For example, let's say we have a mod_perl 1.0 code snippet:
  
    $r->content_type('text/plain');
    $r->print("Hello cruel world!");
  
  If we run this, mod_perl 2.0 will complain that the method
  C<content_type()> can't be found. So we use C<ModPerl::MethodLookup>
  to figure out which module provides this method. We can just run this
  from the command line:
  
    % perl -MApache2 -MModPerl::MethodLookup -le \
      'print((ModPerl::MethodLookup::lookup_method(shift))[0])' \
      content_type
  
  This prints:
  
    to use method 'content_type' add:
             use Apache::RequestRec ();
  
  We do what it says and add this C<use()> statement to our code,
  restart our server (unless we're using
  C<L<Apache::Reload|docs::2.0::api::Apache::Reload>>), and mod_perl
  will no longer complain about this particular method.
  
  Since you may need to use this technique quite often you may want to
  C<L<define an
  alias|docs::2.0::api::ModPerl::MethodLookup/Command_Line_Lookups>>. Once 
  defined the last command line lookup can be accomplished with:
  
    % lookup content_type
  
  =head3 Handling Methods Existing In More Than One Package
  
  Some methods exists in several classes. For example this is the case
  with the C<print()> method. We know the drill:
  
    % lookup print
  
  This prints:
  
    There is more than one class with method 'print'
    try one of:
          use Apache::RequestIO ();
          use Apache::Filter ();
  
  So there is more than one package that has this method. Since we know
  that we call the C<print()> method with the C<$r> object, it must be
  the C<Apache::RequestIO> module that we are after. Indeed, loading
  this module solves the problem.
  
  =head3 Using C<ModPerl::MethodLookup> Programmatically
  
  The issue of picking the right module, when more than one matches, can
  be resolved when using C<ModPerl::MethodLookup> programmatically --
  C<L<lookup_method|docs::2.0::api::ModPerl::MethodLookup/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. C<ModPerl::MethodLookup> knows that C<Apache::RequestIO> and
  and C<Apache::Filter> expect an object of type C<Apache::RequestRec>
  and type C<Apache::Filter> respectively. So in a program running under
  mod_perl we can call:
  
    ModPerl::MethodLookup::lookup_method('print', $r);
  
  Now only one module will be matched.
  
  This functionality can be used in
  C<L<AUTOLOAD|docs::2.0::api::ModPerl::MethodLookup/AUTOLOAD>>, for
  example, although most users will not have a need for this robust of
  solution.
  
  =head3 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
  C<L<preload_all_modules()|docs::2.0::api::ModPerl::MethodLookup/preload_all_modules__>>
  to be the right tool for you. This function preloads B<all> mod_perl
  2.0 modules, implementing their API in 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 B<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.
  
  =head2 Handling Missing and Modified mod_perl 1.0 Methods and Functions
  
  The mod_perl 2.0 API is modelled 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.
  
  If mod_perl 2.0 tells you that some method is missing and it can't be
  found using
  L<ModPerl::MethodLookup|/Using_ModPerl::MethodLookup_to_Discover_Which_mod_perl_2.0_Modules_Need_to_Be_Loaded>,
  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 ditfferent arguments, etc.).
  
  In either of these cases, refer to L<the backwards compatibility
  document|docs::2.0::user::porting::compat/> for an exhaustive list of
  API calls that have been modified or removed.
  
  =head3 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:
  
    $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 C<log_reason()>. But when we use C<ModPerl::MethodLookup> to see
  which module to load in order to call that method, nothing is found:
  
    % perl -MApache2 -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 L<the backwards compatibility
  document|docs::2.0::user::porting::compat/>, wherein we find that as we
  suspected, the method C<log_reason()> no longer exists, and that
  L<instead we should use the other standard logging
  functions|docs::2.0::user::porting::compat/C__r_E_gt_log_reason_>
  provided by the C<Apache::Log> module.
  
  =head3 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:
  
    $parsed_uri = Apache::URI->parse($r, $r->uri);
  
  This code causes mod_perl 2.0 to complain first about not being able
  to load the method C<parse()> via the package Apache::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 C<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 C<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:
  
    $parsed_uri = APR::URI->parse($r->pool, $r->uri);
  
  and all is well in the world again.
  
  =head2 Requiring a specific mod_perl version.
  
  To require a module to run only under 2.0, simply add:
  
    use Apache2;
    use mod_perl 2.0;
  
  META: In fact, before 2.0 is released you really have to say:
  
    use Apache2;
    use mod_perl 1.99;
  
  =head2 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.
  
  Let's say that you have a module C<Apache::Friendly> whose release
  version compliant with mod_perl 1.0 is 1.57. You keep this version on
  CPAN and release a new version, 2.01, which is compliant with mod_perl
  2.0 and preserves the name of the module. It's possible that a user
  may need to have both versions of the module on the same
  machine. Since the two have the same name they obviously cannot live
  under the same tree.
  
  One attempt to solve this problem is to use I<Makefile.PL>'s
  C<MP_INST_APACHE2> option. If the module is configured as:
  
    % perl Makefile.PL MP_INST_APACHE2=1
  
  it'll be installed relative to the I<Apache2/> directory.
  
  META: but of course this won't work in non-core mod_perl, since a
  generic C<Makefile.PL> has no idea what to do about
  C<MP_INST_APACHE2=1>. Need to provide copy-n-paste recipe for this. Or
  even add to the core a supporting module that will handle this
  functionality.
  
  The second step is to change the documentation of your 2.0 compliant
  module to instruct users to C<use Apache2 ();> in their code (or in
  I<startup.pl> or via C<PerlModule Apache2> in I<httpd.conf>) before
  the module is required. This will cause C<@INC> to be modified to
  include the I<Apache2/> directory first.
  
  The introduction of the I<Apache2/> directory is similar to how Perl
  installs its modules in a version specific directory. For example:
  
    lib/5.7.1
    lib/5.7.2
  
  
  =head2 Using C<Apache::compat> As a Tutorial
  
  Even if you have followed the recommendation and eschewed use of the
  C<L<Apache::compat|docs::2.0::api::Apache::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 C<Apache::compt> source code and see
  how the functionality should be implemented in mod_perl 2.0.
  
  For example, mod_perl 2.0 doesn't provide the C<Apache-E<gt>gensym>
  method. As we can see if we look at the C<Apache/compat.pm> source,
  the functionality is now available via the core Perl module C<Symbol>
  and its C<gensym()> function. (Since mod_perl 2.0 works only with Perl
  versions 5.6 and higher, and C<Symbol.pm> is included in the core Perl
  distribution since version 5.6.0, there was no reason to keep
  providing C<Apache-E<gt>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:
  
    my $fh = Symbol::gensym;
    open $fh, $file or die "Can't open $file: $!";
  
  Or we can even skip loading C<Symbol.pm>, since under Perl version 5.6
  and higher we can just do:
  
    open my $fh, $file or die "Can't open $file: $!";
  
  =head1 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. This is the
  case for writers of publically available and CPAN modules who wish to
  continue to maintain a single code base, rather than supplying two
  separate implementations.
  
  =head2 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.
  
  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 variable C<$mod_perl::VERSION>:
  
    use mod_perl;
    use constant MP2 => ($mod_perl::VERSION >= 1.99);
    # ...
    require Symbol if MP2;
    # ...
    
    my $fh = MP2 ? Symbol::gensym : Apache->gensym;
    open $fh, $file or die "Can't open $file: $!";
  
  Here's another way to find out the mod_perl version. In the server
  configuration file you can use a special configuration "define" symbol
  C<MODPERL2>, which is magically enabled internally, as if the server
  had been started with C<-DMODPERL2>.
  
    # in httpd.conf
    <IfDefine MODPERL2>
        # 2.0 configuration
    </IfDefine>
    <IfDefine !MODPERL2>
        # else
    </IfDefine>
  
  From within Perl code this can be tested with
  C<Apache::exists_config_define()>. For example, we can use this method
  to decide whether or not to call C<$r-E<gt>send_http_header()>, which
  no longer exists in mod_perl 2.0:
  
    sub handler {
        my $r = shift;
        $r->content_type('text/html');
        $r->send_http_header() unless Apache::exists_config_define("MODPERL2");
        ...
    }
  
  
  =head1 Maintainers
  
  Maintainer is the person(s) you should contact with updates,
  corrections and patches.
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =head1 Authors
  
  =over
  
  =item *
  
  Nick Tonkin E<lt>nick (at) tonkinresolutions.comE<gt>
  
  =item *
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =back
  
  Only the major authors are listed above. For contributors see the
  Changes file.
  
  =cut
  
  
  

Mime
View raw message