home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2000 May
/
Chip_2000-05_cd1.bin
/
zkuste
/
Perl
/
ActivePerl-5.6.0.613.msi
/
䆊䌷䈹䈙䏵-䞅䞆䞀㡆䞃䄦䠥
/
_7723bb5d5fbc843ad0971040065d3589
< prev
next >
Wrap
Text File
|
2000-03-15
|
8KB
|
244 lines
package SOAP::Packager;
use strict;
use vars qw($VERSION);
use SOAP::Defs;
$VERSION = '0.23';
sub new {
my ($class, $soap_prefix, $depth, $print_fcn) = @_;
my $self = {
soap_prefix => $soap_prefix, # this allows us to turn on/off namespace support
depth => $depth,
print_fcn => $print_fcn,
};
bless $self, $class;
}
sub is_registered {
my ($self, $object) = @_;
$self->{objref_dictionary}{$object}[0]
if exists $self->{objref_dictionary}{$object};
}
sub register {
my ($self, $envelope, $object, $already_serialized) = @_;
#
# $already_serialized is an optional parameter that you can pass as nonzero
# to indicate that the object has been serialized into the stream, but might
# be referred to by other objects. This is used to deal with the special
# cases where roots (body root, and headers) may be referenced, and *could*
# be used to implement the special case of strings/bytearrays, if we can figure
# out a reasonable way of automating string/bytearray matching. I don't expect
# to implement this feature in my serializing (as opposed to deserializing) code
# anytime soon though.
#
#
# my dictionaries spring into life the first time we use them,
# so be careful always to use them via hash references here!
#
if (exists $self->{objref_dictionary}{$object}) {
return $self->{objref_dictionary}{$object}[0];
}
elsif (exists $self->{objref_dictionary_while_sealing}) {
if (exists $self->{objref_dictionary_while_sealing}{$object}) {
return $self->{objref_dictionary_while_sealing}{$object}[0];
}
else {
my $id = $envelope->_alloc_id();
$self->{objref_dictionary_while_sealing}{$object} =
$already_serialized ? [$id] : [$id, $object];
return $id;
}
}
else {
my $id = $envelope->_alloc_id();
$self->{objref_dictionary}{$object} =
$already_serialized ? [$id] : [$id, $object];
return $id;
}
}
sub seal {
my ($self, $envelope) = @_;
#
# NOTE: seal() explicitly supports sealing off multiple times
# to deal with the Envelope/Header/Body special case, where Header
# mustn't have any "external pointers", but may have "internal pointers"
# coming from Body.
# whenever an object is sealed, it is popped from the packager's
# dictionary (the hashed objref-->id mapping is left intact though)
# so that on a reseal, we won't end up reserializing any objects
#
# quit if there's nothing to do
return unless exists $self->{objref_dictionary};
#
# the presence of this member variable indicates that we are sealing
#
my $objref_dictionary_while_sealing =
$self->{objref_dictionary_while_sealing} = {};
my $objref_dictionary = $self->{objref_dictionary};
while (my ($key, $id_and_object) = each %$objref_dictionary) {
if (2 == @$id_and_object) {
$self->seal_object($envelope, @$id_and_object);
pop @{$id_and_object};
}
}
while (%$objref_dictionary_while_sealing) {
#
# first merge newly added items into our main identity table
#
while (my ($key, $id_and_object) = each %$objref_dictionary_while_sealing) {
$self->{objref_dictionary}{$id_and_object->[1]} = $id_and_object;
}
my $prev_dict = $objref_dictionary_while_sealing;
$objref_dictionary_while_sealing =
$self->{objref_dictionary_while_sealing} = {};
#
# finally serialize the items added during the previous pass
#
while (my ($key, $id_and_object) = each %$prev_dict) {
if (2 == @$id_and_object) {
$self->seal_object($envelope, @$id_and_object);
pop @{$id_and_object};
}
}
}
delete $self->{objref_dictionary_while_sealing};
}
sub seal_object {
my ($self, $envelope, $id, $object) = @_;
my $serializer = $envelope->_get_type_mapper()->get_serializer($object);
my ($accessor_uri, $accessor_name) = $serializer->get_typeinfo();
$accessor_name ||= 'item';
my $sp = $self->{soap_prefix};
my $attrs = qq[ ${sp}id="$id"];
my $accessor_type = $serializer->get_accessor_type();
if ($soapperl_accessor_type_simple == $accessor_type) {
my $content = $serializer->serialize_as_string();
my $nsprefix = '';
if (defined $accessor_uri) {
(my $nsdecl, $nsprefix) = $envelope->_get_ns_decl_and_prefix($accessor_uri);
$attrs .= $nsdecl if $nsdecl;
}
my $tag = $nsprefix . $accessor_name;
$self->_print(qq[<$tag$attrs>$content</$tag>]);
return;
}
my $new_depth = $self->{depth} + 1;
my $nsprefix = '';
if (defined $accessor_uri) {
(my $nsdecl, $nsprefix) = $envelope->_push_ns_decl_and_prefix($accessor_uri, $new_depth);
$attrs .= $nsdecl if $nsdecl;
}
my $tag = $nsprefix . $accessor_name;
$self->_print(qq[<$tag$attrs>]);
my $packager = $serializer->is_package() ?
$envelope->_create_new_package($new_depth) : $self;
my $stream = SOAP::OutputStream->new();
$stream->{tag} = $tag;
$stream->{packager} = $packager;
$stream->{envelope} = $envelope;
$stream->{print_fcn} = $self->{print_fcn};
$stream->{soap_prefix} = $self->{soap_prefix};
$stream->{depth} = $new_depth;
$serializer->serialize($stream);
$stream->term();
}
sub _print {
my ($self, $s) = @_;
$self->{print_fcn}->($s);
}
1;
__END__
=head1 NAME
SOAP::Packager - SOAP internal helper class
=head1 SYNOPSIS
use SOAP::Packager;
my $packager = SOAP::Packager->new('s:', 1, sub { print shift } );
# some object used as a reference
my $object = SOAP::Object->new();
# on a given packager, register() always returns the same id for a given object
my $id = $packager->register($env, $object);
unless($id == $packager->register($env, $object)) { die "internal error" }
# this serializes objectA
$packager->seal($envelope);
# note that the package is still valid
unless($id == $packager->register($env, $object)) { die "internal error" }
my $objectB = SOAP::Object->new();
my $idB = $packager->register($env, $objectB);
unless($idB == $packager->register($env, $objectB)) { die "internal error" }
# this just serializes objectB - objectA was already serialized before
$packager->seal($env);
# this does nothing except waste some cycles enumerating a hash table
$packager->seal($env=);
# hash tables shut down at destruction of packager, releasing object references
$packager = undef;
=head1 DESCRIPTION
This is an internal class used by the SOAP/Perl implementation. It is designed to
manage a table of object references and XML ids used for serializing object graphs
that may contain multiref data (and perhaps even cycles). If you are extending
SOAP/Perl, the above synopsis will probably be all you need if you want to reuse this
class. Whatever you pass for the $env reference should implement a function called
_alloc_id that returns a unique string each time it is called. This is normally
implemented by SOAP::Envelope, so you can see a sample implementation there.
=head1 AUTHOR
Keith Brown
=head1 SEE ALSO
SOAP::Envelope
SOAP::OutputStream
=cut