package Bric::App::Handler;
=head1 NAME
Bric::App::Handler - The center of the application, as far as Apache is concerned.
=head1 VERSION
$LastChangedRevision$
=cut
# Grab the Version Number.
require Bric; our $VERSION = Bric->VERSION;
=head1 DATE
$LastChangedDate: 2006-08-07 22:45:13 +0200 (Mon, 07 Aug 2006) $
=head1 SYNOPSIS
use lib '/usr/local/bricolage/lib';
PerlModule Bric::App::Handler
DocumentRoot "/usr/local/bricolage/comp"
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
SetHandler perl-script
PerlAccessHandler Bric::App::AccessHandler
PerlHandler Bric::App::Handler
PerlCleanupHandler Bric::App::CleanupHandler
=head1 DESCRIPTION
This package is the main package used by Apache for managing the Bricolage
application. It loads all the necessary Mason and Bricolage libraries and sets
everything up for use in Apache. It is one function is handler(), which is
called by mod_perl for every request.
=cut
################################################################################
# Dependencies
################################################################################
# Standard Dependencies
use strict;
################################################################################
# Programmatic Dependences
use Bric::Config qw(:mason :sys_user :err :l10n);
use Bric::Util::Fault qw(:all);
use Bric::Util::DBI qw(:trans);
use Bric::Util::Trans::FS;
use Bric::App::Event qw(clear_events);
use Bric::App::Util qw(del_redirect add_msg get_pref);
use Apache::Constants qw(OK);
use Apache::Log;
use HTML::Mason '1.16';
use HTML::Mason::ApacheHandler;
use Bric::App::Callback::AddMore;
use Bric::App::Callback::Alert;
use Bric::App::Callback::Alias;
use Bric::App::Callback::AssetMeta;
use Bric::App::Callback::BulkPublish;
# Only load CharTrans if we have Perl 5.8 or later.
BEGIN { require Bric::App::Callback::CharTrans if ENCODE_OK }
use Bric::App::Callback::ContainerProf;
use Bric::App::Callback::Desk;
use Bric::App::Callback::Event;
use Bric::App::Callback::ListManager;
use Bric::App::Callback::Login;
use Bric::App::Callback::Nav;
use Bric::App::Callback::Perm;
use Bric::App::Callback::Profile;
use Bric::App::Callback::Publish;
use Bric::App::Callback::Request;
use Bric::App::Callback::Search;
use Bric::App::Callback::SelectObject;
use Bric::App::Callback::SelectTime;
use Bric::App::Callback::SiteContext;
use Bric::App::Callback::Workspace;
use Bric::App::Callback::Profile::Action;
use Bric::App::Callback::Profile::AlertType;
use Bric::App::Callback::Profile::Category;
use Bric::App::Callback::Profile::Contrib;
use Bric::App::Callback::Profile::Desk;
use Bric::App::Callback::Profile::Dest;
use Bric::App::Callback::Profile::ElementType;
use Bric::App::Callback::Profile::FieldType;
use Bric::App::Callback::Profile::FormBuilder;
use Bric::App::Callback::Profile::Grp;
use Bric::App::Callback::Profile::Job;
use Bric::App::Callback::Profile::Keyword;
use Bric::App::Callback::Profile::Media;
use Bric::App::Callback::Profile::MediaType;
use Bric::App::Callback::Profile::OutputChannel;
use Bric::App::Callback::Profile::Pref;
use Bric::App::Callback::Profile::Server;
use Bric::App::Callback::Profile::Site;
use Bric::App::Callback::Profile::Source;
use Bric::App::Callback::Profile::Story;
use Bric::App::Callback::Profile::Template;
use Bric::App::Callback::Profile::User;
use Bric::App::Callback::Profile::UserPref;
use Bric::App::Callback::Profile::Workflow;
use MasonX::Interp::WithCallbacks;
{
# Now let's set up our Mason space.
package HTML::Mason::Commands;
# Load all modules to be used from elements.
use Apache::Util qw(escape_uri);
use HTML::Entities (); *escape_html = \&HTML::Entities::encode_entities;
use Bric::Config qw(:auth_len :admin :time :dist :ui :prev :ssl :qa :thumb :oc);
use Bric::Biz::Asset::Business::Media;
use Bric::Biz::Asset::Business::Media::Audio;
use Bric::Biz::Asset::Business::Media::Image;
use Bric::Biz::Asset::Business::Media::Video;
use Bric::Biz::Asset::Business::Parts::Tile::Container;
use Bric::Biz::Element::Container;
use Bric::Biz::Asset::Business::Story;
use Bric::Biz::Asset::Formatting;
use Bric::Biz::Asset::Template;
use Bric::Biz::Site;
use Bric::Biz::AssetType;
use Bric::Biz::ElementType;
use Bric::Biz::Category;
use Bric::Biz::Contact;
use Bric::Biz::Keyword;
use Bric::Biz::Org::Person;
use Bric::Biz::Org::Source;
use Bric::Biz::OutputChannel;
use Bric::Biz::Person;
use Bric::Biz::Person::User;
use Bric::Biz::Workflow qw(:wf_const);
use Bric::Biz::Workflow::Parts::Desk;
use Bric::App::Auth qw(:all);
use Bric::App::Authz qw(:all);
use Bric::App::Cache;
use Bric::App::Event qw(log_event);
use Bric::App::Session qw(:state :user);
use Bric::App::Util qw(:msg
:redir
:pkg
:history
:pref
:aref
:browser
:wf
:sites
:elem
);
use Bric::Dist::Action;
use Bric::Dist::Action::Mover;
use Bric::Dist::Action::Email;
use Bric::Dist::Action::DTDValidate;
use Bric::Util::Job::Dist;
use Bric::Util::Job::Pub;
use Bric::Dist::Resource;
use Bric::Util::AlertType;
use Bric::Util::Burner;
use Bric::Util::Burner::Mason;
use Bric::Util::Class;
use Bric::Util::DBI qw(:junction);
use Bric::Util::Fault qw(:all);
use Bric::Util::Language;
use Bric::Util::Pref;
use Bric::Util::Priv;
use Bric::Util::Priv::Parts::Const qw(:all);
use Bric::Util::Time qw(:all);
use Bric::Util::Trans::FS;
use Bric::Util::UserPref;
use Text::Diff::HTML;
use Text::WordDiff ();
use Bric::SOAP;
use vars qw($c $widget_dir $lang $lang_key $ct);
# Where our widgets live under the element root.
$widget_dir = 'widgets';
# A global that makes the cache available everywhere.
$c = Bric::App::Cache->new;
}
################################################################################
# Inheritance
################################################################################
use base qw( Exporter );
our @EXPORT_OK = qw(handle_err);
our %EXPORT_TAGS = (err => [qw(handle_err)]);
################################################################################
# Function and Closure Prototypes
################################################################################
################################################################################
# Constants
################################################################################
use constant ERROR_FILE =>
Bric::Util::Trans::FS->cat_dir(MASON_COMP_ROOT->[0][1],
Bric::Util::Trans::FS->split_uri(ERROR_URI));
################################################################################
# Fields
################################################################################
# Public Class Fields
################################################################################
# Private Class Fields
my ($ah);
{
my %args = ( comp_root => MASON_COMP_ROOT,
data_dir => MASON_DATA_ROOT,
static_source => MASON_STATIC_SOURCE,
autoflush => 0,
error_mode => 'fatal',
cb_classes => 'ALL',
cb_exception_handler => \&cb_exception_handler,
ignore_nulls => 1,
interp_class => 'MasonX::Interp::WithCallbacks',
decline_dirs => 0,
args_method => MASON_ARGS_METHOD,
preamble => "use utf8;\n",
);
$ah = HTML::Mason::ApacheHandler->new(%args);
}
# This ApacheHandler object will only be used to server components
# that handle errors.
my $gah = HTML::Mason::ApacheHandler->new(comp_root => MASON_COMP_ROOT,
data_dir => MASON_DATA_ROOT,
decline_dirs => 0,
args_method => MASON_ARGS_METHOD);
################################################################################
################################################################################
# Instance Fields
# NONE.
################################################################################
# Class Methods
################################################################################
=head1 INTERFACE
=head2 Constructors
NONE.
=head2 Destructors
NONE.
=head2 Public Class Methods
NONE.
=head2 Public Functions
=over 4
=item my $status = handler()
Handles the apache request.
B None - the buck stops here!
B NONE.
B NONE.
=cut
sub handler {
my ($r) = @_;
# Handle the request.
my $status;
my $lang_name = get_pref('Language');
# A global for localization purposes
local $HTML::Mason::Commands::lang =
Bric::Util::Language->get_handle($lang_name);
local $HTML::Mason::Commands::lang_key = $HTML::Mason::Commands::lang->key;
my $char_set = get_pref('Character Set');
eval {
# Prevent browsers from caching pages.
$r->no_cache(1);
# Set up the language and content type headers.
$r->content_languages([$lang_name]);
$r->content_type('text/html; charset=' . lc $char_set);
Bric::Util::Pref->use_user_prefs(1);
# Start the database transactions.
begin(1);
# Handle the request.
$status = $ah->handle_request($r);
# Commit the database transactions.
commit(1);
Bric::Util::Pref->use_user_prefs(0);
};
# Do error processing, if necessary.
return $@ ? handle_err($r, $@) : $status;
}
################################################################################
=item $status = handle_err($r, $@)
$status = handle_err($r, $@) if $@;
Handles errors when they're thrown by a main handler. Logs the error to the
Apache error log and formats the error screen for the browser.
B NONE.
B NONE.
B NONE.
=cut
sub handle_err {
my ($r, $err) = @_;
$err = Bric::Util::Fault::Exception::AP->new(
error => "Error processing Mason elements.",
payload => $err,
) unless isa_exception($err);
# Rollback the database transactions.
eval { rollback(1) };
my $more_err = $@ ? "In addition, the database rollback failed: $@" : undef;
# Clear out events so that they won't be logged.
clear_events();
# Clear out redirects so that they won't be triggered.
del_redirect();
# Send the error(s) to the apache error log.
$r->log->error($err->full_message);
$r->log->error($more_err) if $more_err;
# Exception::Class::Base provides trace->as_string, but trace_as_text is
# not guaranteed. Use print STDERR to avoid escaping newlines.
print STDERR $err->can('trace_as_text')
? $err->trace_as_text
: join ("\n",
map {sprintf " [%s:%d]", $_->filename, $_->line }
$err->trace->frames),
"\n";
# Process the exception for the user.
# Instead of using $interp->exec we start over a la PreviewHandler.
# The 'BRIC_*' args are used in errors/500.mc
$r->uri(ERROR_URI);
$r->filename(ERROR_FILE);
$r->pnotes('BRIC_EXCEPTION' => $err);
$r->pnotes('BRIC_MORE_ERR' => $more_err);
$gah->handle_request($r);
return OK;
}
##############################################################################
sub cb_exception_handler {
my $err = shift;
rethrow_exception $err unless isa_bric_exception($err, 'Error');
# Rollback any changes.
rollback(1);
begin(1);
add_msg($err->maketext);
}
=back
=head1 PRIVATE
=head2 Private Class Methods
NONE.
=head2 Private Instance Methods
NONE.
=head2 Private Functions
NONE.
=cut
1;
__END__
=head1 NOTES
NONE.
=head1 AUTHOR
David Wheeler
=head1 SEE ALSO
L
=cut