/usr/share/perl5/Pod/WSDL.pm is in libpod-wsdl-perl 0.063-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 | package Pod::WSDL;
# TODO: make array based objects work as own complex types
# TODO: non RPC style bindings
# TODO: read type information alternatively from own file
# TODO: write soapAction attribute in operations?
use strict;
use warnings;
use Carp;
use IO::Scalar;
use Pod::Text;
use Pod::WSDL::Method;
use Pod::WSDL::Return;
use Pod::WSDL::Param;
use Pod::WSDL::Fault;
use Pod::WSDL::Doc;
use Pod::WSDL::Type;
use Pod::WSDL::Writer;
use Pod::WSDL::Utils qw(:writexml :namespaces :messages :types);
use Pod::WSDL::AUTOLOAD;
# -------------------------------------------------------------------------- #
# ------------------ > "CONSTANTS" ----------------------------------------- #
# -------------------------------------------------------------------------- #
our $VERSION = "0.063";
our @ISA = qw/Pod::WSDL::AUTOLOAD/;
our $WSDL_METHOD_REGEXP_BEG = qr/^=(?:begin)\s+wsdl\s*\n(.*?)^=(?:cut|end\s+wsdl).*?^\s*sub\s+(\w+)/ims;
our $WSDL_METHOD_REGEXP_FOR = qr/^=(?:for)\s+wsdl\s*\n(.*?)\n\n^\s*sub\s+(\w+)/ims;
our $WSDL_TYPE_REGEXP_BEG = qr/^=(?:begin)\s+wsdl\s*\n(.*?_ATTR.*?)^=(?:cut|end\s+wsdl)/ims;
our $WSDL_TYPE_REGEXP_FOR = qr/^=(?:for)\s+wsdl\s*\n(.*?_ATTR.*?)\n\n/ims;
our $DEFAULT_BASE_NAME = 'myService';
our $PORT_TYPE_SUFFIX_NAME = 'Handler';
our $BINDING_SUFFIX_NAME = 'SoapBinding';
our $SERVICE_SUFFIX_NAME = 'Service';
# Pod::WSDL::AUTOLOAD uses this
our %FORBIDDEN_METHODS = (
source => {get => 0, set => 0},
source => {get => 0, set => 0},
baseName => {get => 0, set => 0},
methods => {get => 0, set => 0},
location => {get => 1, set => 1},
namespaces => {get => 0, set => 0},
generateNS => {get => 0, set => 0},
types => {get => 0, set => 0},
writer => {get => 0, set => 0},
standardTypeArrays => {get => 0, set => 0},
emptymessagewritten => {get => 0, set => 0},
targetNS => {get => 1, set => 1},
);
# -------------------------------------------------------------------------- #
# --------------- > PUBLIC METHODS ---------------------------------------- #
# -------------------------------------------------------------------------- #
# avoid using reserved words with our autoload methods
# use => pw_use; no not break backward compatibility
sub new {
my ($pkg, %data) = @_;
my $nsnum = 0;
croak "I need a location, died" unless defined $data{location};
croak "I need a file or module name or a filehandle, died" unless defined $data{source};
if ( $data{use} ) {
$data{pw_use} = delete $data{use} ;
}
$data{pw_use} = $LITERAL_USE if $data{style} and $data{style} eq $DOCUMENT_STYLE and !defined $data{pw_use};
$data{pw_use} = $LITERAL_USE and $data{style} = $DOCUMENT_STYLE if $data{wrapped} and !defined $data{pw_use} and !defined $data{style};
my $me = bless {
_source => $data{source},
_baseName => undef,
_methods => [],
_location => $data{location},
_namespaces => {},
_targetNS => undef,
_generateNS => sub {return $DEFAULT_NS_DECL . $nsnum++},
_types => {},
_writer => new Pod::WSDL::Writer(withDocumentation => $data{withDocumentation}, pretty => $data{pretty}),
_standardTypeArrays => {},
_emptymessagewritten => 0,
_pw_use => $data{pw_use} || $ENCODED_USE,
_style => $data{style} || $RPC_STYLE,
_wrapped => $data{wrapped} || 0,
}, $pkg;
croak "'use' argument may only be one of $ENCODED_USE or $LITERAL_USE, died" if $me->pw_use ne $ENCODED_USE and $me->pw_use ne $LITERAL_USE;
croak "'style' argument may only be one of $RPC_STYLE or $DOCUMENT_STYLE, died" if $me->style ne $RPC_STYLE and $me->style ne $DOCUMENT_STYLE;
croak "The combination of use=$ENCODED_USE and style=$DOCUMENT_STYLE is not valid, died" if ($me->style eq $DOCUMENT_STYLE and $me->pw_use eq $ENCODED_USE);
## AHICOX 10/12/2006
## this is a quick and dirty hack to set the baseName
## the baseName should probably be set from the POD
## source (which is why it's set in _getModuleCode)
## this quick hack takes the 'name' parameter when
## we create the object, and
$me->_initSource($data{'source'});
$me->_initNS;
$me->_initTypes;
return $me;
}
sub WSDL {
my $me = shift;
my %args = @_;
my $wr = $me->writer;
$wr->prepare;
if (%args) {
$wr->pretty($args{pretty}) if defined $args{pretty};
$wr->withDocumentation($args{withDocumentation}) if defined $args{withDocumentation};
}
$me->writer->comment("WSDL for " . $me->{_location} . " created by " . ref ($me) . " version: $VERSION on " . scalar localtime);
$me->writer->startTag('wsdl:definitions', targetNamespace => $me->targetNS, %{$me->{_namespaces}});
$me->writer->wrNewLine(2);
$me->_writeTypes;
$_->writeMessages($me->types, $me->style, $me->wrapped) for @{$me->methods};
$me->_writePortType;
$me->_writeBinding;
$me->_writeService;
$me->writer->endTag('wsdl:definitions');
$me->writer->end;
return $me->writer->output;
}
sub addNamespace {
my $me = shift;
my $uri = shift;
my $decl = shift;
croak "I need a namespace, died" unless defined $uri;
defined $decl or $decl = $me->{_generateNS};
$decl = 'xmlns:' . $decl unless $decl =~ /xmlns:/;
$me->{_namespaces}->{$decl} = $uri;
}
# -------------------------------------------------------------------------- #
# ---------------- > INIT METHODS < ---------------------------------------- #
# -------------------------------------------------------------------------- #
sub _initNS {
my $me = shift;
my $namespaces = shift;
$namespaces ||= {};
$me->addNamespace($namespaces->{$_}, $_) for keys %$namespaces;
$me->addNamespace($BASIC_NAMESPACES{$_}, $_) for keys %BASIC_NAMESPACES;
$me->addNamespace($me->targetNS, $IMPL_NS_DECL);
$me->addNamespace($me->targetNS, $TARGET_NS_DECL);
}
sub _initSource {
my $me = shift;
my $src = shift;
my ($baseName, $contents) = $me->_getModuleCode($src, 1);
#set the baseName in the object
$me->baseName($baseName);
# find =begin wsdl ... =end
while ($contents =~ /$WSDL_METHOD_REGEXP_BEG/g) {
$me->_parseMethodPod($2, $1);
}
# find =for wsdl
while ($contents =~ /$WSDL_METHOD_REGEXP_FOR/g) {
$me->_parseMethodPod($2, $1);
}
}
sub _initTypes {
my $me = shift;
for my $method (@{$me->{_methods}}) {
for my $param (@{$method->params},$method->return) {
next unless $param;
unless (exists $XSD_STANDARD_TYPE_MAP{$param->type}) {
$me->_addType($param->type, $param->array);
} elsif ($param->array) {
#AHICOX: 10/10/2006
#changed to _standardTypeArrays (was singular)
$me->{_standardTypeArrays}->{$param->type} = 1;
}
}
for my $fault (@{$method->faults}) {
unless (exists $XSD_STANDARD_TYPE_MAP{$fault->type}) {
$me->_addType($fault->type, 0);
}
}
}
}
sub _addType {
my $me = shift;
my $name = shift;
my $array = shift;
if (exists $me->types->{$name}) {
$me->types->{$name}->array($array) if $array;
return;
}
my $code = $me->_getModuleCode($name);
my $pod = '';
my $in = $code;
my $out = '';
# collect =begin wsdl ... =end
while ($code =~ /$WSDL_TYPE_REGEXP_BEG/g) {
$pod .= "$1\n";
}
# collect =for wsdl
while ($code =~ /$WSDL_TYPE_REGEXP_FOR/g) {
$pod .= "$1\n";
}
warn "No pod wsdl found for type '$name'.\n" unless $pod;
my $IN = new IO::Scalar \$in;
my $OUT = new IO::Scalar \$out;
new Pod::Text()->parse_from_filehandle($IN, $OUT);
$me->types->{$name} = new Pod::WSDL::Type(name => $name, array => $array, pod => $pod, descr => $out, writer => $me->writer);
for my $attr (@{$me->types->{$name}->attrs}) {
unless (exists $XSD_STANDARD_TYPE_MAP{$attr->type}) {
$me->_addType($attr->type, $attr->array);
} elsif ($attr->array) {
#AHICOX: 10/10/2006
#changed to _standardTypeArrays (was singular)
$me->{_standardTypeArrays}->{$attr->type} = 1;
}
}
}
sub _parseMethodPod {
my $me = shift;
my $methodName = shift;
my $podData = shift;
my $method = new Pod::WSDL::Method(name => $methodName, writer => $me->writer);
my @data = split "\n", $podData;
# Preprocess wsdl pod: trim all lines and concatenate lines not
# beginning with wsdl type tokens to previous line.
# Ignore first element, if it does not begin with wsdl type token.
for (my $i = $#data; $i >= 0; $i--) {
if ($data[$i] !~ /^\s*(_INOUT|_IN|_OUT|_RETURN|_DOC|_FAULT|_ONEWAY)/i) {
if ($i > 0) {
$data[$i - 1] .= " $data[$i]";
$data[$i] = '';
}
}
}
for (@data) {
s/\s+/ /g;
s/^ //;
s/ $//;
if (/^_(INOUT|IN|OUT)\s+/i) {
my $param = new Pod::WSDL::Param($_);
$method->addParam($param);
$me->standardTypeArrays->{$param->type} = 1 if $param->array and $XSD_STANDARD_TYPE_MAP{$param->type};
} elsif (/^_RETURN\s+/i) {
my $return = new Pod::WSDL::Return($_);
$method->return($return);
$me->standardTypeArrays->{$return->type} = 1 if $return->array and $XSD_STANDARD_TYPE_MAP{$return->type};
} elsif (/^_DOC\s+/i) {
$method->doc(new Pod::WSDL::Doc($_));
} elsif (/^_FAULT\s+/i) {
$method->addFault(new Pod::WSDL::Fault($_));
} elsif (/^_ONEWAY\s*$/i) {
$method->oneway(1);
}
}
push @{$me->{_methods}}, $method;
}
sub _getModuleCode {
my $me = shift;
my $src = shift;
my $findNS = shift;
if (ref $src and ($src->isa('IO::Handle') or $src->isa('GLOB'))) {
local $/ = undef;
my $contents = <$src>;
$me->_setTargetNS($contents) if $findNS;
##AHICOX: 10/12/2006
##attempt to construct a base name based on the package
my $baseName = $DEFAULT_BASE_NAME;
$src =~ /package\s+(.*?)\s*;/s;
if ($1){
$baseName = $1;
$baseName =~ s/::(.)/uc $1/eg;
}
return ($baseName, $contents);
} else {
my $moduleFile;
if (-e $src) {
$moduleFile = $src;
} else {
my $subDir = $src;
$subDir =~ s!::!/!g;
my @files = map {"$_/$subDir.pm"} @INC;
my $foundPkg = 0;
for my $file (@files) {
if (-e $file) {
$moduleFile = $file;
last;
}
}
}
if ($moduleFile) {
open IN, $moduleFile or die "Could not open $moduleFile, died";
local $/ = undef;
my $contents = <IN>;
close IN;
$me->_setTargetNS($contents) if $findNS;
##AHICOX: 10/12/2006
##attempt to construct a base name based on the package
my $baseName = $DEFAULT_BASE_NAME;
$contents =~ /package\s+(.*?)\s*;/s;
if ($1){
$baseName = $1;
$baseName =~ s/::(.)/uc $1/eg;
}
return ($baseName, $contents);
} else {
die "Can't find any file '$src' and can't locate it as a module in \@INC either (\@INC contains " . join (" ", @INC) . "), died";
}
}
}
sub _setTargetNS {
my $me = shift;
my $contents = shift;
$contents =~ /package\s+(.*?)\s*;/s;
if ($1) {
my $tmp = $1;
$tmp =~ s!::!/!g;
my $serverURL = $me->location;
$serverURL =~ s!(http(s)??://[^/]*).*!$1!;
$me->targetNS("$serverURL/$tmp");
} else {
$me->targetNS($me->location);
}
}
# -------------------------------------------------------------------------- #
# -------------- > OUTPUT UTILITIES < -------------------------------------- #
# -------------------------------------------------------------------------- #
sub _writeTypes {
my $me = shift;
return if keys %{$me->standardTypeArrays} == 0 and keys %{$me->types} == 0;
$me->writer->wrElem($START_PREFIX_NAME, 'wsdl:types');
$me->writer->wrElem($START_PREFIX_NAME, 'schema', targetNamespace => $me->namespaces->{'xmlns:' . $TARGET_NS_DECL}, xmlns => "http://www.w3.org/2001/XMLSchema");
$me->writer->wrElem($EMPTY_PREFIX_NAME, "import", namespace => "http://schemas.xmlsoap.org/soap/encoding/");
for my $type (sort keys %{$me->standardTypeArrays}) {
$me->writer->wrElem($START_PREFIX_NAME, "complexType", name => $ARRAY_PREFIX_NAME . ucfirst $type);
$me->writer->wrElem($START_PREFIX_NAME, "complexContent");
$me->writer->wrElem($START_PREFIX_NAME, "restriction", base => "soapenc:Array");
$me->writer->wrElem($EMPTY_PREFIX_NAME, "attribute", ref => "soapenc:arrayType", "wsdl:arrayType" => 'soapenc:' . $type . '[]');
$me->writer->wrElem($END_PREFIX_NAME, "restriction");
$me->writer->wrElem($END_PREFIX_NAME, "complexContent");
$me->writer->wrElem($END_PREFIX_NAME, "complexType");
}
for my $type (values %{$me->types}) {
$type->writeComplexType($me->types);
}
if ($me->style eq $DOCUMENT_STYLE) {
for my $method (@{$me->methods}) {
$method->writeDocumentStyleSchemaElements($me->types);
}
}
$me->writer->wrElem($END_PREFIX_NAME, 'schema');
$me->writer->wrElem($END_PREFIX_NAME, 'wsdl:types');
$me->writer->wrNewLine;
}
sub _writePortType {
my $me = shift;
$me->writer->wrElem($START_PREFIX_NAME, 'wsdl:portType', name => $me->baseName . $PORT_TYPE_SUFFIX_NAME);
for my $method (@{$me->{_methods}}) {
$method->writePortTypeOperation;
$me->writer->wrNewLine;
}
$me->writer->wrElem($END_PREFIX_NAME, 'wsdl:portType');
$me->writer->wrNewLine(1);
}
sub _writeBinding {
my $me = shift;
$me->writer->wrElem($START_PREFIX_NAME, 'wsdl:binding', name => $me->baseName . $BINDING_SUFFIX_NAME, type => $IMPL_NS_DECL . ':' . $me->baseName . $PORT_TYPE_SUFFIX_NAME);
$me->writer->wrElem($EMPTY_PREFIX_NAME, "wsdlsoap:binding", style => $me->style, transport => "http://schemas.xmlsoap.org/soap/http");
$me->writer->wrNewLine;
for my $method (@{$me->methods}) {
$method->writeBindingOperation($me->targetNS, $me->pw_use);
$me->writer->wrNewLine;
}
$me->writer->wrElem($END_PREFIX_NAME, 'wsdl:binding');
$me->writer->wrNewLine;
}
sub _writeService {
my $me = shift;
$me->writer->wrElem($START_PREFIX_NAME, 'wsdl:service', name => $me->baseName . $PORT_TYPE_SUFFIX_NAME . $SERVICE_SUFFIX_NAME);
$me->writer->wrElem($START_PREFIX_NAME, 'wsdl:port', binding => $IMPL_NS_DECL . ':' . $me->baseName . $BINDING_SUFFIX_NAME, name => $me->baseName);
$me->writer->wrElem($EMPTY_PREFIX_NAME, "wsdlsoap:address", location => $me->location);
$me->writer->wrElem($END_PREFIX_NAME, 'wsdl:port');
$me->writer->wrElem($END_PREFIX_NAME, 'wsdl:service');
$me->writer->wrNewLine;
}
1;
__END__
=head1 NAME
Pod::WSDL - Creates WSDL documents from (extended) pod
=head1 SYNOPSIS
use Pod::WSDL;
my $pod = new Pod::WSDL(source => 'My::Server',
location => 'http://localhost/My/Server',
pretty => 1,
withDocumentation => 1);
print $pod->WSDL;
=head1 DESCRIPTION - How to use Pod::WSDL
=head2 Parsing the pod
How does Pod::WSDL work? If you instantiate a Pod::WSDL object with the name of the module (or the path of the file, or an open filehandle) providing the web service like this
my $pwsdl = new Pod::WSDL(source => 'My::Module',
location => 'http://my.services.location/on/the/web');
Pod::WSDL will try to find C<My::Module> in C<@INC>, open the file, parse it for WSDL directives and prepare the information for WSDL output. By calling
$pwsdl->WSDL;
Pod::WSDL will output the WSDL document. That's it.
When using Pod::WSDL, the parser expects you to do the following:
=over 2
=item *
Put the pod directly above the subroutines which the web service's client is going to call. There may be whitespace between the pod and the sub declaration but nothing else.
=item *
Use the C<=begin>/C<=end> respectively the C<=for> directives according to standard pod: anything between C<=begin WSDL> and C<=end> will be treated as pod. Anything composing a paragraph together with C<=for WSDL> will be treated as pod.
=back
Any subroutine not preceded by WSDL pod will be left unmentioned. Any standard pod will be ignored (though, for an exception to this, see the section on own complex types below).
The individual instructions for Pod::WSDL always begin with a keyword, like C<_RETURN> or C<_DOC> or C<_FAULT>. After this different things may follow, according to the specific type of instruction. The instruction may take one or more lines - everything up to the next line beginning with a keyword or the end of the pod is belonging to the current instruction.
=head2 Describing Methods
How do we use Pod::WSDL? In describing a web service's method we have to say something about parameters, return values and faults. In addition you might want to add some documentation to these items and to the method itself.
=head3 Parameters
WSDL differentiates between in-, out- and inout-parameters, so we do that, too. A different matter is the question, if the client can do this too, but now we are talking about possibilities, not actualities.
The pod string describing a parameter has the structure
(_IN|_OUT|_INOUT) NAME ($|@)TYPE DESCRIPTION
like
_IN foo $string This is a foo
or
_INOUT bar @bar An array of bars
You will easily guess what C<_IN>, C<_OUT> and C<_INOUT> stand for so we can move on. C<NAME> is the name of your parameter. It does not have any real function (the order of the parameters being the only important thing) but it is nice to have it since in a WSDL document the parameters need to have names. So instead of having Pod::WSDL automatically generate cryptic names (it cannot do that right now) be nice to the client and use some sensible name. The C<TYPE> of the parameters can be any of the xsd (schema) standard types (see [5]) or a type of your own creation. The C<$> resp. C<@> symbols tell Pod::WSDL and your client if it is a scalar or array parameter. Everything following the type up to the next instruction is treated as the parameter's documentation. If you call the constructor of Pod::WSDL with the argument C<withDocumentation =E<gt> 1>, it will be added to the WSDL.
=head3 Return Values
Return values work like parameters but since in WSDL there is provision for only one return value (you have (in)out parameters, or can return arrays if that isn't enough), you do not need to give them a name. Pod::WSDL will automatically call them 'Return' in the WSDL document. So, the structure of C<_RETURN> instructions is
_RETURN ($|@)TYPE DESCRIPTION
as in
_RETURN $string Returns a string
The pod for one method may only have one C<_RETURN> instruction. If you don't specify a C<_RETURN> instruction, Pod::WSDL will assume that you return void. Of course the perl subroutine still will return something, but your web service won't. To make this clear Pod::WSDL generates an empty response message for this.
If you want some method to be a one way operation (see [4], ch. 2.4.1), say so by using the instruction C<_ONEWAY> in the pod. In this case no response message will be generated and a C<_RETURN> instruction will be ignored.
=head3 Faults
SOAP faults are usually translated into exceptions in languages like Java. If you set up a web service using SOAP::Lite, SOAP will trap your dying program and generate a generic fault using the message of C<die>. It is also possible to access SOAP::Lite's SOAP::Fault directly if you want more control - but this is not our issue. If you want to use custom-made fault messages of your own, define them in C<_FAULT> instructions, which look like this:
_FAULT TYPE DESCRIPTION
An example could be the following:
_FAULT My::Fault If anything goes wrong
Since you probably won't return an array of fault objects, you do not need to use the C<($|@)> tokens. Just say that you return a fault, declare its type and add an optional description.
As with parameters (but in contrary to C<_RETURN> instructions) you can declare as many C<_FAULT> instructions as you like, providing for different exception types your method might throw.
=head3 Method Documentation
Method documentation is easily explained. Its structure is
_DOC Here comes my documentation ...
That's it. Use several lines of documentation if you like. If you instantiate the Pod::WSDL object with the parameter C<withDocumentation =E<gt> 1>, it will be written into the WSDL document.
=head2 Describing Modules - Using Own Complex Types
Quite often it will be the case that you have to use complex types as parameters or return values. One example of this we saw when talking about faults: you might want to create custom fault types (exceptions) of your own to fullfill special needs in the communication between web service and client. But of course you also might simply want to pass a complex parameter like a address object containing customer data to your application. WSDL provides the means to describe complex types borrowing the xsd schema syntax. Pod::WSDL makes use of this by allowing you to add WSDL pod to your own types. Assuming you have some own type like
package My::Type;
sub new {
bless {
foo => 'foo',
bar => -1
}, $_[0];
}
1;
simply describe the keys of your blessed hash like this.
=begin WSDL
_ATTR foo $string A foo
_ATTR bar $integer And a bar
=end WSDL
Put this pod anywhere within the package My::Type. Pod::WSDL will find it (if it is in @INC), parse it and integrate it into the WSDL document. The C<_ATTR> instruction works exactly as the C<_IN>, C<_OUT> and C<_INOUT> instructions for methods (see above).
If you initialize the Pod::WSDL object using C<withDocumentation =E<gt> 1>, Pod::WSDL will look for standard pod in the module, parse it using Pod::Text and put it into the WSDL document.
=head1 METHODS
=head2 new
Instantiates a new Pod::WSDL.
=head3 Parameters
=over 4
=item
source - Name of the source file, package of the source module or file handle on source file for which the WSDL shall be generated. This source must contain specialized Pod tags. So, if your source is '/some/directory/modules/Foo/Bar.pm' with package declaration 'Foo::Bar', source may be '/some/directory/modules/Foo/Bar.pm' or 'Foo::Bar' (in which case '/some/directory/modules' has to be in @INC) or an open file handle on the file. Right?
=item
location - Target namespace for the WSDL, usually the full URL of your webservice's proxy.
=item
pretty - Pretty print WSDL, if true. Otherwise the WSDL will come out in one line. The software generating the client stubs might not mind, but a person reading the WSDL will!
=item
withDocumentation - If true, put available documentation in the WSDL (see "Pod Syntax" above). For used own complex types ('modules') this will be the output of Pod::Text on these modules. The software generating the client stubs might give a damn, but a person reading the WSDL won't!
=back
=head2 WSDL
Returns WSDL as string.
=head3 Parameters
=over 4
=item
pretty - Pretty print WSDL, if true. Otherwise the WSDL will come out in one line. The software generating the client stubs might not mind, but a person reading the WSDL will!
=item
withDocumentation - If true, put available documentation in the WSDL (see "Pod Syntax" above). For used own complex types ('modules') this will be the output of Pod::Text on these modules. The software generating the client stubs might give a damn, but a person reading the WSDL won't!
=back
=head2 addNamespace
Adds a namespace. Will be taken up in WSDL's definitions element.
=head3 Parameters
=over 4
=item 1
URI of the namespace
=item 2
Declarator of the namespace
=back
=head1 EXTERNAL DEPENDENCIES
Carp
XML::Writer
IO::Scalar
Pod::Text
The test scripts use
XML::XPath
=head1 EXAMPLES
see the *.t files in the distribution
=head1 BUGS
Please send me any bug reports, I will fix them or mention the bugs here :-)
=head1 TODO
=head2 Describe Several Signatures for one Method
Of course, one subroutine declaration might take a lot of different sets of parameters. In Java or C++ you would have to have several methods with different signatures. In perl you fix this within the method. So why not put several WSDL pod blocks above the method so the web service's client can handle that.
=head2 Implement a Better Parsing of the pod
Right know, the pod is found using some rather complex regular expressions. This is evil and will certainly fail in some situations. So, an issue on top of the fixme list is to switch to regular parsing. I'm not sure if I can use Pod::Parser since I need the sub declaration outside the pod, too.
=head2 Handle Several Package Declarations in One File
So far, Pod::WSDL assumes a one to one relation between packages and files. If it meets several package declarations in one file, it will fail some way or the other. For most uses, one package in one file will presumably suffice, but it would be nice to be able to handle the other cases, too.
=head2 Handle Array based blessed References
Array based blessed references used for complex types are something of a problem.
=head2 Get Information on Complex Types from Somewhere Else
If you use complex types for parameters that are not your own (we assume, that the module containing the web service always is your own), you might not be able to put the WSDL pod into the module files. So why not fetch it from somewhere else like a configuration file?
=head2 Integrate Pod::WSDL with SOAP::Lite
With Axis, you simply call the web service's URL with the parameter '?wsdl' and you get the WSDL document. It would be nice to be able to do this with SOAP::Lite, too.
=head2 Implement Non RPC Style Messages
Pod::WSDL writes WSDL documents in encoded RPC style. It should be able to generate literal RPC and document styles, too.
=head1 REFERENCES
[1] L<http://ws.apache.org/axis/>
[2] L<http://search.cpan.org/~kbrown/SOAP-0.28/>
[3] L<http://search.cpan.org/~byrne/SOAP-Lite-0.65_5/>
[4] L<http://www.w3.org/TR/wsdl.html>
[5] L<http://www.w3.org/TR/xmlschema-2/>
=head1 SEE ALSO
http://ws.apache.org/axis/
http://search.cpan.org/~kbrown/SOAP-0.28/
http://search.cpan.org/~byrne/SOAP-Lite-0.65_5/
http://www.w3.org/TR/wsdl
WSDL::Generator (a different way to do it)
SOAP::WSDL (the client side)
SOAP::Clean::WSDL (I have not tried this)
=head1 AUTHOR
Tarek Ahmed, E<lt>bloerch -the character every email address contains- oelbsk.orgE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2006 by Tarek Ahmed
This library is alpha software and comes with no warranty whatsoever.
It is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.5 or,
at your option, any later version of Perl 5 you may have available.
=cut
|