home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 May / Chip_2000-05_cd1.bin / zkuste / Perl / ActivePerl-5.6.0.613.msi / 䆊䌷䈹䈙䏵-䞅䞆䞀㡆䞃䄦䠥 / _f1d431aad8be3db7de5567bde86d6f97 < prev    next >
Text File  |  2000-03-15  |  11KB  |  337 lines

  1. package SOAP::GenericInputStream;
  2.  
  3. use strict;
  4. use vars qw($VERSION);
  5. use SOAP::Defs;
  6. use SOAP::TypeMapper;
  7.  
  8. $VERSION = '0.23';
  9.  
  10. ########################################################################
  11. # constructor
  12. ########################################################################
  13. sub new {
  14.     my ($class, $typeuri, $typename, $resolver, $type_mapper) = @_;
  15.  
  16.     $type_mapper ||= SOAP::TypeMapper->defaultMapper();
  17.  
  18.     my $self = {
  19.         resolver    => $resolver,
  20.         diags       => 'root',
  21.         type_mapper => $type_mapper,
  22.         hash        => {},
  23.         text        => '',
  24.         has_accessors => 0,
  25.     };
  26.  
  27.     $self->{$soapperl_intrusive_hash_key_typeuri}  = $typeuri  if $typeuri;
  28.     $self->{$soapperl_intrusive_hash_key_typename} = $typename if $typename;
  29.  
  30.     bless $self, $class;
  31. }
  32.  
  33. ########################################################################
  34. # interface ISoapStream
  35. ########################################################################
  36. sub content {
  37. #   my ($self, $text) = @_;
  38.     &_content;
  39. }
  40. sub simple_accessor {
  41. #   my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $content) = @_;
  42.     &_simple_accessor;
  43. }
  44.  
  45. sub compound_accessor {
  46. #    my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $is_package, $resolver) = @_;
  47.     &_compound_accessor;
  48. }
  49.  
  50. sub reference_accessor {
  51. #    my ($self, $accessor_uri, $accessor_name, $object) = @_;
  52.     &_reference_accessor;
  53. }
  54.  
  55. sub forward_reference_accessor {
  56. #    my ($self, $accessor_uri, $accessor_name) = @_;
  57.     &_forward_reference_accessor;
  58. }
  59.  
  60. sub term {
  61. #   my ($self) = @_;
  62.     &_term;
  63. }
  64.  
  65. ########################################################################
  66. # implementation
  67. ########################################################################
  68. sub _content {
  69.     my ($self, $text) = @_;
  70.  
  71.     $self->{text} = $text;
  72. }
  73. sub _simple_accessor {
  74.     my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $content) = @_;
  75.  
  76.     #
  77.     # TBD: perform appropriate transformation based on $typename
  78.     #
  79.  
  80.     ++$self->{has_accessors};
  81.  
  82.     $self->_add_accessor($accessor_name, $content);
  83. }
  84.  
  85. sub _compound_accessor {
  86.     my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $is_package, $resolver) = @_;
  87.  
  88.     my $my_resolver = sub {
  89.         my $child_object = shift;
  90.         $self->_add_accessor($accessor_name, $child_object);
  91.         $resolver->($child_object) if $resolver;
  92.     };
  93.  
  94.     my $stream = $self->{type_mapper}->get_deserializer($typeuri,
  95.                                                         $typename,
  96.                                                         $my_resolver);
  97.  
  98.     ++$self->{has_accessors};
  99.  
  100.     #
  101.     # DIAGS
  102.     #
  103.     {
  104.         my $typename_or_undef = defined($typename) ? $typename : '<undef>';
  105.         $stream->{diags} = "parent accessor: <$accessor_name>, type: $typename_or_undef";
  106.     }
  107.     $stream;
  108. }
  109.  
  110. sub _reference_accessor {
  111.     my ($self, $accessor_uri, $accessor_name, $object) = @_;
  112.  
  113.     ++$self->{has_accessors};
  114.  
  115.     $self->_add_accessor($accessor_name, $object);
  116. }
  117.  
  118. sub _forward_reference_accessor {
  119.     my ($self, $accessor_uri, $accessor_name) = @_;
  120.  
  121.     ++$self->{has_accessors};
  122.  
  123.     # return a closure to complete the transaction at a later date
  124.     sub { $self->_add_accessor($accessor_name, shift) };
  125. }
  126.  
  127. sub _term {
  128.     my ($self) = @_;
  129.  
  130.     my $text = $self->{text};
  131.     my $hash = $self->{hash};
  132.  
  133.     #
  134.     # to determine whether this is a hash or a scalar node,
  135.     # see if there were any accessors
  136.     #
  137.     my $object;
  138.     if ($self->{has_accessors}) {
  139.     #
  140.     # there were accessors, so verify that there was no
  141.     # non-whitespace text interspersed in between them
  142.     #
  143.     if ($text =~ /\S/) {
  144.         die "Found non-whitespace content between accessors: [$text]";
  145.     }
  146.     $object = $self->{hash};
  147.     }    
  148.     else {
  149.     $object = $self->{text};
  150.     }
  151.  
  152.     $hash->{$soapperl_intrusive_hash_key_typeuri}  = $self->{$soapperl_intrusive_hash_key_typeuri}  if exists $self->{$soapperl_intrusive_hash_key_typeuri};
  153.     $hash->{$soapperl_intrusive_hash_key_typename} = $self->{$soapperl_intrusive_hash_key_typename} if exists $self->{$soapperl_intrusive_hash_key_typename};
  154.  
  155.     $self->{resolver}->($object);
  156. }
  157.  
  158. #############################################################
  159. # misc
  160. #############################################################
  161. sub _add_accessor {
  162.     my ($self, $accessor_name, $object) = @_;
  163.  
  164.     my $hash = $self->{hash};
  165.  
  166.     if (exists $hash->{$accessor_name}) {
  167.         die "Duplicate accessor: $accessor_name"
  168.     }
  169.     $hash->{$accessor_name} = $object;
  170. }
  171.  
  172. 1;
  173.  
  174. __END__
  175.  
  176. =head1 NAME
  177.  
  178. SOAP::GenericInputStream - Default handler for SOAP::Parser output
  179.  
  180. =head1 SYNOPSIS
  181.  
  182.     use SOAP::Parser;
  183.   
  184.     my $parser = SOAP::Parser->new();
  185.  
  186.     $parser->parsefile('soap.xml');
  187.  
  188.     my $headers = $parser->get_headers();
  189.     my $body    = $parser->get_body();
  190.  
  191.  
  192. =head1 DESCRIPTION
  193.  
  194. As you can see from the synopsis, you won't use SOAP::GenericInputStream
  195. directly, but rather the SOAP::Parser will create instances of it when
  196. necessary to unmarshal SOAP documents.
  197.  
  198. The main reason for this documentation is to describe the interface
  199. exposed from SOAP::GenericInputStream because you need to implement this
  200. interface if you'd like to have the parser create something more exotic
  201. than what SOAP::GenericInputStream produces.
  202.  
  203. =head2 new(TypeUri, TypeName, Resolver)
  204.  
  205. TypeUri and TypeName are strings that indicate the type of object being
  206. unmarshaled. Resolver is a function pointer takes a single argument,
  207. the resulting object, and you should call through this pointer in your
  208. implementation of term (which means you need to store it until term is
  209. called). Here's an example of a minimal implementation, assuming you've
  210. stored the object reference in $self->{object}:
  211.  
  212.     sub new {
  213.         my ($class, $typeuri, $typename, $resolver) = @_;
  214.         return bless { resolver => $resolver }, $class;
  215.     }
  216.  
  217.     sub term {
  218.         my ($self) = @_;
  219.         $self->{resolver}->($self->{object});
  220.     }
  221.  
  222. =head2 simple_accessor(AccessorUri, AccessorName, TypeUri, TypeName, Content)
  223.  
  224. SOAP::Parser calls this function when it encounters a simple (scalar) accessor.
  225. You are told the uri and name of both the accessor and any xsi:type attribute.
  226. If the packet being unmarshaled doesn't use namespaces (this is possible but isn't
  227. recommended by the SOAP spec), AccessorUri will be undefined. Unless there is an
  228. explicit xsi:type, TypeUri and TypeName will also be undefined. So the only two
  229. parameters that are guaranteed to be defined are AccessorName and Content.
  230.  
  231. AccessorUri and AccessorName gives the namespace and name of the element,
  232. and Content contains the scalar content (always a string).
  233.  
  234. =head2 compound_accessor(AccessorUri, AccessorName, TypeUri, TypeName, IsPackage, Resolver)
  235.  
  236.  
  237. SOAP::Parser calls this function when it encounters a compound accessor (e.g.,
  238. a structured type whose value is inlined under the accessor). The first four
  239. parameters here are as described in simple_accessor above. IsPackage is a hint
  240. that tells you that this node is a package (generally you can ignore this; SOAP::Parser
  241. does all the work to deal with packages). Resolver may or may not be defined,
  242. and I'll discuss how it works shortly.
  243.  
  244. This function must return a blessed object reference that implements the
  245. same interface (nothing prohibits you from simply returning $self, but since SOAP::Parser
  246. keeps track of these object references on a per-node basis, it's usually easier just
  247. to create a new instance of your class and have each instance know how to unmarshal
  248. a single object).
  249.  
  250. If Resolver is defined, you'll need to call it when the new stream is term'd to
  251. communicate the resulting object reference to the Parser, so be sure to propagate
  252. this reference to the new stream you create to do the unmarshaling. Since you probably
  253. also need to be notified when the new object is created, you'll not normally hand Resolver
  254. directly to the new stream, but rather you'll provide your own implementation of Resolver
  255. that does something with the object and then chains to the Resolver passed in from the
  256. parser:
  257.  
  258.     sub compound_accessor {
  259.         my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $is_package, $resolver) = @_;
  260.  
  261.         my $object = $self->{object};
  262.  
  263.         # create a closure to pass to the new input stream
  264.         my $my_resolver = sub {
  265.             my ($newly_unmarshaled_object) = @_;
  266.  
  267.             # do something with the object yourself
  268.             $object->{$accessor_name} = $newly_unmarshaled_object;
  269.  
  270.             # chain to the Parser's resolver if it's defined
  271.             $resolver->($child_object) if $resolver;
  272.         };
  273.  
  274.         return $self->{type_mapper}->get_deserializer($typeuri, $typename, $my_resolver);
  275.     }
  276.  
  277. =head2 reference_accessor(AccessorUri, AccessorName, Object)
  278.  
  279. SOAP::Parser calls this function when it encounters a reference to an object that
  280. it's already unmarshaled. AccessorUri and AccessorName are the same as in simple_accessor,
  281. and Object is a reference to a thingy; it's basically whatever was resolved when
  282. another stream (perhaps one that you implemented) unmarshaled the thingy. This could
  283. be a blessed object reference, or simply a reference to a scalar (in SOAP it is possible
  284. to communicate pointers to multiref scalars). In any case, you should add this new
  285. reference to the object graph. Here's a simple example:
  286.  
  287.     sub reference_accessor {
  288.         my ($self, $accessor_uri, $accessor_name, $object) = @_;
  289.  
  290.         $self->{object}{$accessor_name} = $object;
  291.     }
  292.  
  293. =head2 forward_reference_accessor(AccessorUri, AccessorName)
  294.  
  295. SOAP::Parser calls this function when it encounters a reference to an object that
  296. has not yet been unmarshaled (a forward reference). You should return a function
  297. pointer that expects a single argument (the unmarshaled object). This can be as simple
  298. as creating a closure that simply delays a call to reference_accessor on yourself:
  299.  
  300.  
  301.     sub forward_reference_accessor {
  302.         my ($self, $accessor_uri, $accessor_name) = @_;
  303.  
  304.         # return a closure to complete the transaction at a later date
  305.         return sub {
  306.             my $object = @_;
  307.             $self->reference_accessor($accessor_uri, $accessor_name, $object);
  308.         };
  309.     }
  310.  
  311. =head2 term()
  312.  
  313. SOAP::Parser calls this function when there are no more accessors for the given node.
  314. You are expected to call the Resolver you were passed at construction time at this point
  315. to pass the unmarshaled object reference to your parent. Note that due to forward
  316. references, the object may not be complete yet (it may have oustanding forward references
  317. that haven't yet been resolved). This isn't a problem, because the parse isn't finished
  318. yet, and as long as you've provided a resolver that fixes up these object references
  319. from your implementation of forward_reference_accessor, by the time the parse is complete,
  320. your object have all its references resolved by the parser.
  321.  
  322. See the description of new() for an example implementation of this function.
  323.  
  324. =head1 DEPENDENCIES
  325.  
  326. SOAP::TypeMapper
  327.  
  328. =head1 AUTHOR
  329.  
  330. Keith Brown
  331.  
  332. =head1 SEE ALSO
  333.  
  334. perl(1).
  335.  
  336. =cut
  337.