/lib/Apache/Voodoo/Loader/Dynamic.pm

https://github.com/gitpan/Apache-Voodoo · Perl · 187 lines · 110 code · 41 blank · 36 comment · 9 complexity · 1c619b76731ed3af59ac057e8fd821d5 MD5 · raw file

  1. package Apache::Voodoo::Loader::Dynamic;
  2. $VERSION = "3.0200";
  3. use strict;
  4. use warnings;
  5. use base("Apache::Voodoo::Loader");
  6. sub new {
  7. my $class = shift;
  8. my $self = {};
  9. bless $self,$class;
  10. $self->{'module'} = shift;
  11. $self->{'bootstrapping'} = 1;
  12. $self->refresh;
  13. $self->{'bootstrapping'} = 0;
  14. $self->{'parents'} = {};
  15. foreach (eval '@{'.$self->{'module'}.'::ISA}') {
  16. $self->{'parents'}->{$_} = $self->get_mtime($_);
  17. }
  18. return $self;
  19. }
  20. sub init {
  21. my $self = shift;
  22. $self->{'config'} = \@_;
  23. $self->{'object'}->init(@_);
  24. }
  25. sub get_mtime {
  26. my $self = shift;
  27. my $file = shift || $self->{'module'};
  28. $file =~ s/::/\//go;
  29. $file .= ".pm";
  30. return 0 unless defined($INC{$file});
  31. my $mtime = (stat($INC{$file}))[9];
  32. return $mtime;
  33. }
  34. sub refresh {
  35. my $self = shift;
  36. $self->{'object'} = $self->load_module;
  37. $self->{'mtime'} = $self->get_mtime;
  38. # zap our created closures.
  39. foreach my $method (keys %{$self->{'provides'}}) {
  40. # a little help from the Cookbook 10.14
  41. no strict 'refs';
  42. no warnings 'redefine';
  43. *$method = undef;
  44. }
  45. $self->{'provides'} = {};
  46. }
  47. #
  48. # Override the built in 'can' to allow:
  49. # a) trigger dynamically reloading the module as needed
  50. # b) dynamically create closures to link Apache::Voodoo::Handler with the controllers
  51. #
  52. sub can {
  53. my $self = shift;
  54. my $method = shift;
  55. my $nosub = shift;
  56. # find out if this thing has changed
  57. if ($self->{'mtime'} != $self->get_mtime) {
  58. $self->refresh;
  59. $self->{'object'}->init(@{$self->{'config'}});
  60. }
  61. if (defined $self->{'provides'}->{$method}) {
  62. return 1;
  63. }
  64. elsif ($self->{'object'}->isa("Apache::Voodoo::Zombie") || $self->{'object'}->can($method)) {
  65. # Either we have a dead module and we map whatever was requested or
  66. # we have a live one and has the requested method.
  67. # cache the existance of this method
  68. $self->{'provides'}->{$method} = 1;
  69. # If we used the autoloader to get here, then we want to keep using
  70. # it. Bypass the creation of the closure.
  71. unless ($nosub) {
  72. # create a closeure for this method (a little help from the Cookbook 10.14)
  73. no strict 'refs';
  74. no warnings 'redefine';
  75. *$method = sub { my $self = shift; return $self->_handle($method,@_); };
  76. }
  77. return 1;
  78. }
  79. return 0;
  80. }
  81. #
  82. # In scnearios where the caller doesn't know that can has been overloaded, we'll use
  83. # autoload to catch it and call our overloaded can. We unfortunately end up with two
  84. # different ways to do a very similar task because the constraints are slightly different.
  85. # We want the calls from the A::V::Handler to the controllers to be aware of what methods
  86. # actually exist so it can either call them or not. The controllers talking to the models
  87. # shouldn't have to do anything special or even be aware that they're talking to this
  88. # proxy object, thus the need for a autoload variation.
  89. #
  90. sub AUTOLOAD {
  91. next unless ref($_[0]);
  92. our $AUTOLOAD;
  93. my $method = $AUTOLOAD;
  94. $method =~ s/.*:://;
  95. my $self = shift;
  96. if ($self->can($method,'1')) {
  97. return $self->_handle($method,@_);
  98. }
  99. # we don't handle this one
  100. next;
  101. }
  102. # now we need a stub for destroy to keep autoloader happy.
  103. sub DESTROY { }
  104. sub _handle {
  105. my $self = shift;
  106. my $method = shift;
  107. my @params = @_;
  108. # check parent modules for change
  109. foreach my $module (eval '@{'.$self->{'module'}.'::ISA}') {
  110. my $t = $self->get_mtime($module);
  111. if ($self->{'parents'}->{$module} != $t) {
  112. $self->{'parents'}->{$module} = $t;
  113. my $file = $module;
  114. $file =~ s/::/\//go;
  115. $file .= ".pm";
  116. no warnings 'redefine';
  117. delete $INC{$file};
  118. eval {
  119. no warnings 'redefine';
  120. require $file;
  121. };
  122. if ($@) {
  123. my $error= "There was an error loading one of the base classes for this page ($_):\n\n$@\n";
  124. my $link = $self->{'module'};
  125. $link =~ s/::/\//g;
  126. unless ($method eq "handle") {
  127. $link =~ s/([^\/]+)$/$method."_".$1/e;
  128. }
  129. # FIXME replace with a instance of Apache::Voodoo::Zombie
  130. $self->debug("ZOMBIE: $self->{'module'} $method");
  131. return $self->display_error($error,"/$link");
  132. }
  133. }
  134. }
  135. return $self->{'object'}->$method(@params);
  136. }
  137. 1;
  138. ################################################################################
  139. # Copyright (c) 2005-2010 Steven Edwards (maverick@smurfbane.org).
  140. # All rights reserved.
  141. #
  142. # You may use and distribute Apache::Voodoo under the terms described in the
  143. # LICENSE file include in this package. The summary is it's a legalese version
  144. # of the Artistic License :)
  145. #
  146. ################################################################################