File Coverage

blib/lib/SAP/BC/XMLRFC.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package SAP::BC::XMLRFC;
2              
3              
4 1     1   703 use strict;
  1         3  
  1         31  
5              
6 1     1   5 use SAP::BC;
  1         2  
  1         18  
7 1     1   655 use SAP::BC::Iface;
  1         3  
  1         36  
8 1     1   8 use HTTP::Request;
  1         2  
  1         21  
9 1     1   6 use HTTP::Cookies;
  1         2  
  1         22  
10 1     1   6 use LWP::UserAgent;
  1         1  
  1         21  
11 1     1   1751 use XML::Parser;
  0            
  0            
12              
13              
14             use Data::Dumper;
15              
16              
17              
18             use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
19              
20             require Exporter;
21              
22              
23             @ISA = qw(Exporter);
24             # Items to export into callers namespace by default. Note: do not export
25             # names by default without a very good reason. Use EXPORT_OK instead.
26             # Do not simply export all your public functions/methods/constants.
27              
28             @EXPORT_OK = qw (
29             Iface
30             xmlrfc
31             );
32              
33             # Global debug flag
34              
35             my $DEBUG = undef;
36              
37             # Valid parameters
38             my $VALID = {
39             SERVER => 1,
40             BC => 1,
41             USERID => 1,
42             PASSWD => 1
43             };
44              
45             my $_out = "";
46             my $_cell = "";
47             my $_tagre = "";
48              
49             $VERSION = '0.06';
50              
51             # Preloaded methods go here.
52              
53              
54             sub new {
55              
56             my $proto = shift;
57             my $class = ref($proto) || $proto;
58             my $self = {
59             @_
60             };
61              
62             die "Server not supplied !" if ! exists $self->{SERVER};
63             die "SAP BC USERID not supplied !" if ! exists $self->{USERID};
64             die "SAP BC Password not supplied (PASSWD) !" if ! exists $self->{PASSWD};
65              
66             # Validate parameters
67             map { delete $self->{$_} if ! exists $VALID->{$_} } keys %{$self};
68              
69             # check that the service exists
70             $self->{BC} = new SAP::BC(
71             server => $self->{SERVER},
72             user => $self->{USERID},
73             password => $self->{PASSWD}
74             );
75             # create the object and return it
76             bless ($self, $class);
77             return $self;
78             }
79              
80              
81             # method to dynamically create functions SAP::BC::Iface
82             sub Iface{
83              
84             my $self = shift;
85             my $service = shift;
86             die "No Service name supplied to lookup " if ! $service;
87             die "Service does not exist - $service " if ! exists $self->{BC}->services->{$service};
88             my $lookup = "/invoke/sap.rfc/createTemplate";
89              
90             $self->{BC}->_prime_ua();
91             my $ua = $self->{BC}->{ua};
92              
93             # print STDERR "REQ: ".$self->{SERVER}.$lookup."\?\$call\=true\&serverName\=".
94             # $self->{BC}->services->{$service}->{sapsys}.
95             # "\&\$rfcname\_search\=\&groupname=\&\$rfcname\=".
96             # $self->{BC}->services->{$service}->{rfcname}.
97             # "\&table=\&submit\=RFC\-XML" ."\n";
98             my $req = new HTTP::Request('GET', $self->{SERVER}.$lookup."\?\$call\=true\&serverName\=".
99             $self->{BC}->services->{$service}->{sapsys}.
100             "\&\$rfcname\_search\=\&groupname=\&\$rfcname\=".
101             $self->{BC}->services->{$service}->{rfcname}.
102             "\&table=\&submit\=RFC\-XML" );
103              
104             $req->authorization_basic($self->{USERID},$self->{PASSWD});
105              
106             my $res = $ua->request($req);
107              
108             die " Interface lookup call failed: " . $res->message() if !$res->is_success();
109              
110             my $content = $res->content;
111             die "RFC_SYSTEM_FAILURE in interface lookup" if $content =~ /RFC_ERROR/s;
112             my ( $xml_template ) =
113             $content =~ /^.*xmlData<\/B><\/TD>\s*(.*?)<\/TD>.*$/s;
114              
115             my $p = new XML::Parser( Style => 'Tree',
116             ErrorContext => 3 );
117              
118             my $r = $p->parse( $xml_template );
119              
120             my $intrfc = $self->{BC}->services->{$service}->{rfcname};
121             $intrfc =~ s/\//\_\-/g;
122             die "Interface lookup failed for $service " unless
123             $r->[1]->[8]->[3] eq "rfc:".$intrfc;
124              
125             my $iface = new SAP::BC::Iface( NAME => $service );
126              
127             # shift over to the interface definition part of the doc
128             $r = $r->[1]->[8]->[4];
129             my $c = -1;
130             while (my $parmname = $r->[$c+=4]){
131             # print STDERR " Parm: $parmname \n";
132             my $parm = $r->[$c + 1];
133             # determine a table or structure or simple parameter
134             if ( $parm->[3] =~ /\w/){
135             # we have either a structure or a table
136             if ( $parm->[3] =~ /item/ ){
137             # we have a table
138             my $struct = SAP::BC::Struc->new( NAME => $parmname );
139             # add fields
140             my $d = -1;
141             while ( my $fieldname = $parm->[4]->[$d+=4] ){
142             # fudge for a bad last one ?
143             next unless $fieldname =~ /\w/;
144             $struct->addField( NAME => $fieldname,
145             TYPE => 'chars' );
146             };
147             $iface->addTab( NAME => $parmname,
148             STRUCTURE => $struct );
149             } else {
150             # we have a structure
151             my $struct = SAP::BC::Struc->new( NAME => $parmname );
152             my $d = -1;
153             while ( my $fieldname = $parm->[$d+=4] ){
154             # fudge for a bad last one ?
155             next unless $fieldname =~ /\w/;
156             $struct->addField( NAME => $fieldname,
157             TYPE => 'chars' );
158             };
159             $iface->addParm( NAME => $parmname,
160             TYPE => 'chars',
161             STRUCTURE => $struct );
162             };
163             } else {
164             $iface->addParm( NAME => $parmname,
165             TYPE => 'chars' );
166             };
167             };
168              
169             # print STDERR "Iface: ".Dumper($iface);
170             return $iface;
171              
172             }
173              
174              
175             # Call The Function module
176             sub xmlrfc {
177             my $xml_out = "";
178             my $intrfc = "";
179             my $self = shift;
180             my $iface = shift;
181             my $ref = ref($iface);
182             die "this is not an Interface Object!"
183             unless $ref eq "SAP::BC::Iface" and $ref;
184              
185             $self->{BC}->_prime_ua();
186             my $ua = $self->{BC}->{ua};
187              
188             my $service = $iface->name();
189             # print STDERR "The services- $service -: ".Dumper( $self->{BC}->services);
190             $intrfc = $self->{BC}->services->{$service}->{rfcname};
191             $intrfc =~ s/\//\_\-/g;
192             $service =~ s/\:/\//;
193             my $req = new HTTP::Request('POST', $self->{SERVER}."/invoke/".$service);
194             $req->header('Content-Type' => 'application/x-sap.rfc');
195             #'Host' => 'my.source.host.net');
196              
197             $req->authorization_basic($self->{USERID},$self->{PASSWD});
198              
199             my $start_content = <
200            
201            
202            
203             BC1
204             BC2
205            
206            
207             ENDOFSTART
208              
209             my $end_content = <
210            
211            
212             ENDOFEND
213              
214             $xml_out = "
215             " xmlns:rfc=\"urn:sap-com:document:sap:rfc:functions\">\n";
216              
217             map{
218             $xml_out.= " <" . $_->name .">";
219             if (my $s = $_->structure ){
220             $xml_out.= "\n";
221             map { $xml_out.= " <" . $_ .">" . $s->Fieldvalue($_) .
222             "<\/" . $_ . ">\n" ;
223             } ( $s->Fields );
224             $xml_out.= " <\/" . $_->name . ">\n" ;
225             } else {
226             $xml_out.= $_->value . "<\/" . $_->name . ">\n" ;
227             };
228             } ( $iface->Parms );
229             map{ my $tab = $_;
230             $xml_out.= " <" . $tab->name . ">\n";
231             while ( my $row = $tab->nextrow ){
232             $xml_out .= " \n";
233             map { $xml_out .= " <$_>$row->{$_}<\/$_>\n" } keys %{$row};
234             $xml_out .= " <\/item>\n";
235             };
236             # map { $xml_out .= " <" . $_ . ">" . "<\/" . $_ . ">\n";
237             # } ( $tab->structure->Fields );
238             $xml_out.= " <\/" . $tab->name . ">\n"
239             } ( $iface->Tabs );
240              
241             $xml_out .= "<\/rfc:".$intrfc.">\n";
242             # print STDERR "the constructed interface: ".$start_content.$xml_out.$end_content;
243              
244             $req->content($start_content.$xml_out.$end_content);
245              
246             my $res = $ua->request($req);
247              
248             die " RFC-XML call failed: " . $res->as_string() if !$res->is_success();
249              
250             $xml_out = $res->content;
251             # print $xml_out;
252             die "RFC_SYSTEM_FAILURE in interface lookup".$xml_out if $xml_out =~ /RFC_ERROR/s;
253              
254             my $p = new XML::Parser( Style => 'Tree',
255             ErrorContext => 3
256             );
257              
258             # pick properly handled RFC errors
259             my ($faultcode, $faultstring, $faultname) =
260             $xml_out =~ /^.*?\(.*?)\<\/faultcode\>.*?
261             \(.*?)\<\/faultstring\>.*?
262             \(.*?)\<\/name\>.*$/sx;
263             die "RFX-XML call error: ".$faultcode." ".$faultstring." ".$faultname if $faultcode;
264              
265             my $r = $p->parse( $xml_out );
266              
267             $r = $r->[1]->[4]->[4];
268             my $c = -1;
269             while (my $parmname = $r->[$c+=4]){
270             my $parm = $r->[$c + 1];
271             # is this a table ?
272             if ( $parm->[3] eq 'item' ){
273             $iface->Tab($parmname)->empty;
274             # process each row
275             my $i = -1;
276             while ($parm->[$i+=4] eq 'item'){
277             # process each field
278             my $row = $parm->[$i + 1];
279             my @row = ();
280             my $j = -1;
281             while ( my $field = $row->[$j+=4] ){
282             push( @row, $row->[$j + 1]->[2] );
283             };
284             $iface->Tab($parmname)->addrow(\@row);
285             };
286             } else {
287             # is it a complex parameter
288             $iface->addParm( SAP::BC::Parms->new( NAME => $parmname,
289             TYPE => 'chars') );
290             if ( $parm->[3] =~ /\w/ ){
291             my $struct = SAP::BC::Struc->new( NAME => $parmname );
292             my $d = -1;
293             while ( my $fieldname = $parm->[$d+=4] ){
294             # fudge for a bad last one ?
295             next unless $fieldname =~ /\w/;
296             my $field = $parm->[$d + 1];
297             $struct->addField( NAME => $fieldname,
298             TYPE => 'chars',
299             VALUE => $field->[2]);
300             };
301             $iface->Parm($parmname)->structure( $struct );
302             } else {
303             # Simple Parameter
304             $iface->Parm($parmname)->value($parm->[2]);
305             };
306             };
307             };
308             }
309              
310             sub disconnect {
311             my $self = shift;
312             $self->{'BC'}->disconnect();
313             }
314              
315             # Autoload methods go after =cut, and are processed by the autosplit program.
316              
317             # Below is the stub of documentation for your module. You better edit it!
318              
319             =head1 NAME
320              
321             SAP::BC::XMLRFC - Perl extension for performing RFC Function calls against an SAP R/3 using the Business Connector System. Please refer to the README file found with this distribution.
322              
323             =head1 SYNOPSIS
324              
325             # Setup up a service in the SAP BC server for an RFC-XML based call to RFC_READ_REPORT
326             # called test:ReadReport to make this example work
327              
328             use SAP::BC::XMLRFC;
329             $rfc = new SAP::BC::XMLRFC( );
330              
331             my $userid = 'testuser';
332             my $passwd = 'letmein';
333             my $server="http://my.server.blah:5555";
334             my $service = 'test:ReadReport';
335              
336             # build the connecting object
337             my $xmlrfc = new SAP::BC::XMLRFC( SERVER => $server,
338             USERID => $userid,
339             PASSWD => $passwd );
340             # Discover the interface definition for a function module
341             my $i = $xmlrfc->Iface( $service );
342              
343             # set a parameter value of the interface
344             $i->Parm('PROGRAM')->value('SAPLGRAP');
345              
346             # call the BC service with an interface object
347             $xmlrfc->xmlrfc( $i );
348              
349             print "Name:", $i->Parm('TRDIR')->structure->NAME, "\n";
350             map {print @{$_}, "\n" } ( $i->Tab('QTAB')->rows );
351              
352             while ( my $row = $i->Tab('QTAB')->nextrow ){
353             map { print "$_ = $row->{$_} \n" } keys %{$row};
354             };
355              
356              
357             =head1 DESCRIPTION
358              
359             Enabler for XMLRFC calls to SAP vi athe SAP Business Connector
360              
361             =head1 METHODS:
362              
363             my $rfc = new SAP::BC::XMLRFC( SERVER => $server,
364             USERID => $userid,
365             PASSWD => $passwd );
366              
367              
368             =head1 AUTHOR
369              
370             Piers Harding, saprfc@kogut.demon.co.uk.
371              
372             But Credit must go to all those that have helped.
373              
374              
375             =head1 SEE ALSO
376              
377             perl(1), SAP::BC(3), SAP::BC::XMLRFC(3), SAP::BC::Iface(3)
378              
379             =cut
380              
381             1;