1############################################################################### 2# 3# This file copyright (c) 2001-2011 Randy J. Ray, all rights reserved 4# 5# Copying and distribution are permitted under the terms of the Artistic 6# License 2.0 (http://www.opensource.org/licenses/artistic-license-2.0.php) or 7# the GNU LGPL (http://www.opensource.org/licenses/lgpl-2.1.php). 8# 9############################################################################### 10# 11# Description: This is the RPC::XML::ParserFactory class, a factory for 12# classes that derive from the RPC::XML::Parser class. 13# 14# Functions: import 15# new 16# register 17# 18# Libraries: RPC::XML::Parser::XMLParser \ 19# RPC::XML::Parser::XMLLibXML > One (or more) of these 20# RPC::XML::Parser::XMLSAX / 21# 22# Global Consts: $VERSION 23# 24# Environment: None. 25# 26############################################################################### 27 28package RPC::XML::ParserFactory; 29 30use 5.008008; 31use strict; 32use warnings; 33use vars qw($VERSION %AVAILABLE $PARSER_CLASS); 34use subs qw(import new register); 35 36# Because this is a factory class, there are some eval's that violate this 37# critic policy, but can't be worked around: 38## no critic (RequireCheckingReturnValueOfEval) 39 40$VERSION = '1.03'; 41$VERSION = eval $VERSION; ## no critic (ProhibitStringyEval) 42 43# These are the known parsers supported, not including any that are specified 44# by the user at import-time. 45$PARSER_CLASS = 'XML::Parser'; 46%AVAILABLE = ( 47 'XML::Parser' => 'RPC::XML::Parser::XMLParser', 48 'XML::LibXML' => 'RPC::XML::Parser::XMLLibXML', 49); 50 51# "Normalize" the key-names to allow some simplicity (and sugar): 52for (keys %AVAILABLE) 53{ 54 my $key = lc $_; 55 $AVAILABLE{$key} = $AVAILABLE{$_}; 56 $key =~ s/:://g; 57 $AVAILABLE{$key} = $AVAILABLE{$_}; 58} 59 60############################################################################### 61# 62# Sub Name: import 63# 64# Description: Method called when this module is use'd 65# 66# Arguments: NAME IN/OUT TYPE DESCRIPTION 67# $class in scalar Class name (not used) 68# @args in list Arguments to the import 69# 70# Globals: $PARSER_CLASS 71# 72# Returns: void 73# 74############################################################################### 75sub import 76{ 77 my (undef, @args) = @_; 78 79 # As a special-case, this one parameter might be specified without the 80 # key, if it is the ONLY thing passed: 81 if (1 == @args) 82 { 83 @args = (class => @args); 84 } 85 86 # For now, the only arguments are key/value pairs so it's safe to coerce 87 # this into a hash 88 my %argz = @args; 89 90 # In fact, for now, this is the only argument: 91 if ($argz{class}) 92 { 93 $PARSER_CLASS = $argz{class}; 94 } 95 96 return; 97} 98 99############################################################################### 100# 101# Sub Name: new 102# 103# Description: Constructor. Save any important attributes, leave the 104# heavy lifting for the parse() routine and XML::Parser. 105# 106# Arguments: NAME IN/OUT TYPE DESCRIPTION 107# $class in scalar Class we're initializing 108# %attr in hash Any extras the caller wants 109# 110# Globals: $RPC::XML::ERROR 111# 112# Returns: Success: object ref 113# Failure: undef 114# 115############################################################################### 116sub new 117{ 118 my ($class, %attrs) = @_; 119 120 my $factory = delete $attrs{class} || $PARSER_CLASS; 121 122 if ($class = $AVAILABLE{$factory}) 123 { 124 eval "require $class;"; ## no critic (ProhibitStringyEval) 125 if ($@) 126 { 127 $RPC::XML::ERROR = __PACKAGE__ . "::new: Error loading $class (" . 128 "factory for '$factory'): $@"; 129 return; 130 } 131 } 132 else 133 { 134 # This means that the class is not one of the built-in ones. Try to 135 # load it, then make sure it's a sub-class of this one: 136 $class = $factory; 137 eval "require $class;"; ## no critic (ProhibitStringyEval) 138 if ($@) 139 { 140 $RPC::XML::ERROR = __PACKAGE__ . "::new: Error loading $class: $@"; 141 return; 142 } 143 # Loaded OK... is it a descendent? 144 if (! $class->isa(__PACKAGE__)) 145 { 146 $RPC::XML::ERROR = __PACKAGE__ . "::new: Class '$class' cannot " . 147 'be used, as it is not a sub-class of ' . __PACKAGE__; 148 return; 149 } 150 } 151 152 return $class->new(%attrs); 153} 154 1551; 156 157__END__ 158 159=head1 NAME 160 161RPC::XML::ParserFactory - A factory class for RPC::XML::Parser objects 162 163=head1 SYNOPSIS 164 165 use RPC::XML::ParserFactory; 166 ... 167 $P = RPC::XML::ParserFactory->new(); 168 $P->parse($message); 169 170=head1 DESCRIPTION 171 172The B<RPC::XML::ParserFactory> class encapsulates the process of creating 173parser objects that adhere to the interface described in 174L<RPC::XML::Parser|RPC::XML::Parser>. Under the hood, the parser object 175created and returned could be from any of a number of implementation classes. 176 177=head1 IMPORT-TIME ARGUMENTS 178 179You can specify a particular underlying parser class to use, if you do not 180want B<RPC::XML::ParserFactory> to use the default class. This is done with 181the C<class> keyword: 182 183 use RPC::XML::ParserFactory (class => 'XML::Parser'); 184 185The value may be the name for any of the built-in classes, or it may be the 186name of a class that inherits from B<RPC::XML::Parser> (and can thus be 187"manufactured" by the factory). The value is saved and becomes the default 188class for any calls to B<new> that do not explicitly name a class to use. 189 190Note that if the specified class is not valid, this is not tested until the 191first call to B<new>, at which point an invalid class will cause an exception 192(error) to occur. The constructor will return C<undef> and the 193B<$RPC::XML::ERROR> variable will contain the error message. 194 195=head2 Names of Built-In Parsers 196 197The following names are valid when specified as the value of the C<class> 198argument described above: 199 200=over 4 201 202=item XML::Parser 203 204=item xml::parser 205 206=item xmlparser 207 208All of these specify the parser implementation based on the B<XML::Parser> 209module. This is the default parser if the user does not specify any 210alternative. 211 212=item XML::LibXML 213 214=item xml::libxml 215 216=item xmllibxml 217 218These specify a parser implementation based on the B<XML::LibXML> module. 219This is a new parser and not as well-vetted as the previous one, hence it 220must be explicitly requested. 221 222=back 223 224=head1 SUBROUTINES/METHODS 225 226The methods are: 227 228=over 4 229 230=item new([ARGS]) 231 232Create a new instance of the class. Any extra data passed to the constructor 233is taken as key/value pairs (B<not> a hash reference) and attached to the 234object. 235 236This method passes all arguments on to the new() method of the chosen 237implementation class, except for the following: 238 239=over 4 240 241=item class NAME 242 243If the user chooses, they may specify an explicit class to use for parsers 244when calling new(). If passed, this overrides any value that was given at 245use-time (processed by import()). 246 247=back 248 249=back 250 251=head1 DIAGNOSTICS 252 253The constructor returns C<undef> upon failure, with the error message available 254in the global variable B<C<$RPC::XML::ERROR>>. 255 256=head1 BUGS 257 258Please report any bugs or feature requests to 259C<bug-rpc-xml at rt.cpan.org>, or through the web interface at 260L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=RPC-XML>. I will be 261notified, and then you'll automatically be notified of progress on 262your bug as I make changes. 263 264=head1 SUPPORT 265 266=over 4 267 268=item * RT: CPAN's request tracker 269 270L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=RPC-XML> 271 272=item * AnnoCPAN: Annotated CPAN documentation 273 274L<http://annocpan.org/dist/RPC-XML> 275 276=item * CPAN Ratings 277 278L<http://cpanratings.perl.org/d/RPC-XML> 279 280=item * Search CPAN 281 282L<http://search.cpan.org/dist/RPC-XML> 283 284=item * MetaCPAN 285 286L<https://metacpan.org/release/RPC-XML> 287 288=item * Source code on GitHub 289 290L<http://github.com/rjray/rpc-xml> 291 292=back 293 294=head1 LICENSE AND COPYRIGHT 295 296This file and the code within are copyright (c) 2011 by Randy J. Ray. 297 298Copying and distribution are permitted under the terms of the Artistic 299License 2.0 (L<http://www.opensource.org/licenses/artistic-license-2.0.php>) or 300the GNU LGPL 2.1 (L<http://www.opensource.org/licenses/lgpl-2.1.php>). 301 302=head1 CREDITS 303 304The B<XML-RPC> standard is Copyright (c) 1998-2001, UserLand Software, Inc. 305See L<http://www.xmlrpc.com> for more information about the B<XML-RPC> 306specification. 307 308=head1 SEE ALSO 309 310L<RPC::XML|RPC::XML>, L<RPC::XML::Client|RPC::XML::Client>, 311L<RPC::XML::Server|RPC::XML::Server>, L<XML::Parser|XML::Parser> 312 313=head1 AUTHOR 314 315Randy J. Ray C<< <rjray@blackperl.com> >> 316 317=cut 318