File Coverage

blib/lib/Flash/FLAP.pm
Criterion Covered Total %
statement 27 126 21.4
branch 0 28 0.0
condition 0 3 0.0
subroutine 9 23 39.1
pod 0 10 0.0
total 36 190 18.9


line stmt bran cond sub pod time code
1             package Flash::FLAP;
2              
3 1     1   6932 use 5.00000;
  1         4  
  1         40  
4 1     1   7 use strict;
  1         1  
  1         43  
5              
6             require Exporter;
7 1     1   5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         13  
  1         183  
8             @ISA = qw(Exporter);
9              
10             # Items to export into callers namespace by default. Note: do not export
11             # names by default without a very good reason. Use EXPORT_OK instead.
12             # Do not simply export all your public functions/methods/constants.
13              
14             # This allows declaration use Flash::FLAP ':all';
15             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
16             # will save memory.
17             %EXPORT_TAGS = ( 'all' => [ qw(
18            
19             ) ] );
20              
21             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
22              
23             @EXPORT = qw(
24            
25             );
26              
27             $VERSION = '0.09';
28              
29              
30             =head1 NAME
31              
32             Flash::FLAP - Flash Remoting in Perl
33             Translated from PHP Remoting v. 0.5b from the -PHP project.
34              
35             Main gateway class. This is always the file you call from flash remoting-enabled server scripts.
36              
37             =head1 SYNOPSIS
38              
39             This code should be present in your FLAP gateway script, the one called by the Flash client.
40            
41             To enable the client to call method bar() under service Foo,
42             make sure MyCLass has a method called bar() and register an instance of your class.
43              
44             my $object = new MyClass();
45             my $flap = FLAP->new;
46             $flap->registerService("Foo",$object);
47             $flap->service();
48              
49             Or, if you have many services to register, create a package corresponding to each service
50             and put them into a separate directory. Then register this directory name.
51              
52             In the example below directory "services" may contain Foo.pm, Bar.pm etc.
53             Therefore, services Foo and Bar are available. However, these packages must have a function
54             called methodTable returning the names and descriptions of all possible methods to invoke.
55             See the documentation and examples for details.
56              
57             my $flap = FLAP->new;
58             $flap->setBaseClassPath('./services');
59             $flap->service();
60              
61              
62              
63             =head1 ABSTRACT
64              
65             Macromedia Flash Remoting server-side support.
66              
67             =head1 DESCRIPTION
68              
69             This file accepts the data and deserializes it using the InputStream and Deserializer classes.
70             Then the gateway builds the executive class which then loads the targeted class file
71             and executes the targeted method via flash remoting.
72             After the target uri executes the the gateway determines the data type of the data
73             and serializes and returns the data back to the client.
74              
75              
76             =head2 EXPORT
77              
78             None by default.
79              
80             =head1 SEE ALSO
81              
82             There is a mailing list for Flash::FLAP. You can subscribe here:
83             http://lists.sourceforge.net/lists/listinfo/flaph-general
84              
85             The web page for the package is at:
86             http://www.simonf.com/flap
87              
88             =head1 AUTHOR
89              
90             Vsevolod (Simon) Ilyushchenko, simonf@simonf.com
91              
92             =head1 COPYRIGHT AND LICENSE
93              
94             Copyright (c) 2003 by Vsevolod (Simon) Ilyushchenko. All rights reserved.
95              
96             This library is free software; you can redistribute it and/or modify it
97             under the same terms as Perl itself.
98             The code is based on the -PHP project (http://amfphp.sourceforge.net/)
99              
100             ORIGINAL PHP Remoting CONTRIBUTORS
101             Musicman - original design
102             Justin - gateway architecture, class structure, datatype io additions
103             John Cowen - datatype io additions, class structure
104             Klaasjan Tukker - modifications, check routines, and register-framework
105              
106             ==head1 CHANGES
107              
108             =head2 Sat Mar 13 16:25:00 EST 2004
109              
110             =item Patch from Kostas Chatzikokolakis handling encoding.
111              
112             Sat Aug 2 14:01:15 EDT 2003
113             Changed new() to be invokable on objects, not just strings.
114              
115             Sun Jul 20 19:27:44 EDT 2003
116             Added "binmode STDIN" before reading input to prevent treating 0x1a as EOF on Windows.
117              
118             Wed Apr 23 19:22:56 EDT 2003
119             Added "binmode STDOUT" before printing headers to prevent conversion of 0a to 0d0a on Windows.
120             Added modperl 1 support and (so far commented out) hypothetical modperl 2 support.
121              
122             Sun Mar 23 13:27:00 EST 2003
123             Synching with AMF-PHP:
124             Added functions debugDir() and log() (debug() in PHP), added reading headers to service().
125             Added fromFile() to enable parsing traffic dumps.
126            
127             =cut
128              
129             # load the required system packagees
130 1     1   707 use Flash::FLAP::IO::InputStream;
  1         3  
  1         31  
131 1     1   679 use Flash::FLAP::IO::Deserializer;
  1         3  
  1         28  
132 1     1   585 use Flash::FLAP::App::Executive;
  1         3  
  1         29  
133 1     1   643 use Flash::FLAP::IO::Serializer;
  1         3  
  1         31  
134 1     1   605 use Flash::FLAP::IO::OutputStream;
  1         2  
  1         32  
135 1     1   519 use Flash::FLAP::Util::Object;
  1         2  
  1         1317  
136              
137             my $exec;
138              
139             # constructor
140             sub new
141             {
142 0     0 0   my ($proto) = @_;
143 0   0       my $class = ref($proto) || $proto;
144 0           my $self = {};
145 0           bless $self, $class;
146 0           $self->{exec} = new Flash::FLAP::App::Executive();
147 0           $self->{debug}=0;
148 0           return $self;
149             }
150              
151             sub debug
152             {
153 0     0 0   my $self = shift;
154 0 0         if (@_) {$self->{debug} = shift;}
  0            
155 0           return $self->{debug};
156             }
157              
158             sub service
159             {
160 0     0 0   my ($self)=@_;
161              
162 0           my $inputStream;
163 0           my $content = "";
164            
165             #Otherwise Apache on Windows treats 0x1a as EOF.
166 0           binmode STDIN;
167              
168 0 0         if($ENV{MOD_PERL})
169             {
170 0           require mod_perl;
171 0           my $MP2 = ($mod_perl::VERSION >= 1.99);
172 0 0         if ($MP2)
173             {
174 0           die "Modperl2 is not supported yet. If you would like to use Flash::FLAP under modperl2 , please drop me a note at simonf\@simonf.com.\n";
175             #eval
176             #{
177             # require Apache::RequestUtil;
178             # require Apache::RequestReq;
179             #};
180             #if ($@)
181             #{
182             # die "Running under mod_perl 2 but could not load Apache::RequestUtil: $@\n";
183             #}
184             #my $r = Apache->request();
185             #Apache::RequestReq->read($r, $content, $r->header_in('Content-Length'));
186             }
187             else
188             {
189 0           eval {require Apache;};
  0            
190 0 0         if ($@)
191             {
192 0           die "Running under mod_perl 1 but could not load Apache::Request: $@\n";
193             }
194 0           my $r = Apache->request();
195 0           $r->read($content, $r->header_in('Content-Length'));
196             }
197             }
198             else
199             {
200 0           $content = do { local $/, <> }; #read the whole STDIN into one variable
  0            
201             }
202              
203 0           $self->_service($content);
204              
205             }
206              
207             sub fromFile
208             {
209 0     0 0   my ($self, $file) = @_;
210              
211 0 0         $file = $self->debugDir."input.amf" unless $file;
212              
213             # temporary load the contents from a file
214 0           my $content = $self->_loadRawDataFromFile($file);
215              
216             # build the input stream object from the file contents
217 0           my $inputStream = new Flash::FLAP::IO::InputStream($content);
218            
219             # build the deserializer and pass it a reference to the inputstream
220 0           my $deserializer = new Flash::FLAP::IO::Deserializer($inputStream, $self->{encoding});
221            
222             # get the returned Object
223 0           my $amfin = $deserializer->getObject();
224              
225 0           return $amfin;
226             }
227              
228             sub _service
229             {
230 0     0     my ($self, $content) = @_;
231            
232 0 0         if($self->debug)
233             {
234             # WATCH OUT, THIS IS NOT THREAD SAFE, DON'T USE IN CONCURRENT ENVIRONMENT
235             # temporary load the contents from a file
236 0           $content = $self->_loadRawDataFromFile($self->debugDir."/input.amf");
237            
238             # save the raw amf data to a file
239             #$self->_saveRawDataToFile ($self->debugDir."/input.amf", $content);
240             }
241            
242             # build the input stream object from the file contents
243 0           my $inputStream = new Flash::FLAP::IO::InputStream($content);
244            
245             # build the deserializer and pass it a reference to the inputstream
246 0           my $deserializer = new Flash::FLAP::IO::Deserializer($inputStream, $self->{encoding});
247            
248             # get the returned Object
249 0           my $amfin = $deserializer->getObject();
250            
251             # we can add much functionality with the headers here, like turn on server debugging, etc.
252 0           my $headercount = $amfin->numHeader();
253            
254 0           for (my $i=0; $i<$headercount; $i++)
255             {
256 0           my $header = $amfin->getHeaderAt($i);
257 0 0         if ($header->{'key'} eq "DescribeService")
258             {
259 0           $self->{exec}->setHeaderFilter("DescribeService");
260             }
261             # other headers like net debug config
262             # and Credentials
263             }
264              
265            
266             # get the number of body elements
267 0           my $bodycount = $amfin->numBody();
268            
269             # create Object for storing the output
270 0           my $amfout = new Flash::FLAP::Util::Object();
271            
272             # loop over all of the body elements
273 0           for (my $i=0; $i<$bodycount; $i++)
274             {
275 0           my $body = $amfin->getBodyAt($i);
276             # set the packagePath of the executive to be our method's uri
277             #Simon - unused for now
278 0           $self->{exec}->setTarget( $body->{"target"} );
279             #/Simon
280             # execute the method and pass it the arguments
281 0           my $results = $self->{exec}->doMethodCall( $body->{"value"} );
282             # get the return type
283 0           my $returnType = $self->{exec}->getReturnType();
284             # save the result in our amfout object
285 0           $amfout->addBody($body->{"response"}."/onResult", "null", $results, $returnType);
286             }
287            
288             # create a new output stream
289 0           my $outstream = new Flash::FLAP::IO::OutputStream ();
290              
291             # create a new serializer
292 0           my $serializer = new Flash::FLAP::IO::Serializer ($outstream, $self->{encoding});
293            
294             # serialize the data
295 0           $serializer->serialize($amfout);
296              
297 0           if(0)
298             {
299             # save the raw data to a file for debugging
300             $self->_saveRawDataToFile ($self->debugDir."/results.amf", $outstream->flush());
301             }
302              
303             # send the correct header
304 0           my $response = $outstream->flush();
305 0           my $resLength = length $response;
306              
307             #Necessary on Windows to prevent conversion of 0a to 0d0a.
308 0           binmode STDOUT;
309              
310 0           print <
311             Content-Type: application/x-amf
312             Content-Length: $resLength
313              
314             EOF
315             # flush the amf data to the client.
316 0           print $response;
317              
318 0           return $self;
319            
320             }
321              
322             sub debugDir
323             {
324 0     0 0   my ($self, $dir) = @_;
325 0 0         $self->{debugDir} = $dir if $dir;
326 0           return $self->{debugDir};
327             }
328              
329              
330             sub setBaseClassPath
331             {
332 0     0 0   my ($self, $path) = @_;
333 0 0         if (-d $path)
334             {
335 0           $self->{exec}->setBaseClassPath($path);
336             }
337             else
338             {
339 0           print STDERR "Directory $path does not exist and could not be registered.\n";
340 0           die;
341             }
342             }
343              
344             sub registerService
345             {
346 0     0 0   my ($self, $package, $servicepackage) = @_;
347 0           $self->{exec}->registerService($package, $servicepackage);
348             }
349              
350             sub setSafeExecution
351             {
352 0     0 0   my ($self, $safe) = @_;
353 0           print STDERR "There is no need to call setSafeExecution anymore!\n";
354             }
355              
356             sub encoding
357             {
358 0     0 0   my $self = shift;
359 0 0         $self->{encoding} = shift if @_;
360 0           return $self->{encoding};
361             }
362              
363             # usefulldebugging method
364             # You can save the raw data sent from the
365             # flash client by calling
366             # $self->_saveRawDataToFile("file.amf", $contents);
367              
368             sub _saveRawDataToFile
369             {
370 0     0     my ($self, $filepath, $data)=@_;
371             # open the file for writing
372 0 0         if (!open(HANDLE, "> $filepath"))
373             {
374 0           die "Could not open file $filepath: $!\n";
375             }
376             # write to the file
377 0 0         if (!print HANDLE $data)
378             {
379 0           die "Could not print to file $filepath: $!\n";
380             }
381             # close the file resource
382 0           close HANDLE;
383             }
384              
385             sub _appendRawDataToFile
386             {
387 0     0     my ($self, $filepath, $data) = @_;
388             # open the file for writing
389 0 0         if (!open (HANDLE, ">>$filepath"))
390             {
391 0           die "Could not open file $filepath: $!\n";
392             }
393             # write to the file
394 0 0         if (!print HANDLE $data)
395             {
396 0           die "Could not print to file $filepath: $!\n";
397             }
398             # close the file resource
399 0           close HANDLE;
400             }
401              
402              
403             # get contents of a file into a string
404             sub _loadRawDataFromFile
405             {
406 0     0     my ($self, $filepath)=@_;
407             # open a handle to the file
408 0           open (HANDLE, $filepath);
409             # read the entire file contents
410 0           my @contents = ;
411             # close the file handle
412 0           close HANDLE;
413             # return the contents
414 0           return join "", @contents;
415             }
416              
417             sub log
418             {
419 0     0 0   my ($self, $content) = @_;
420 0           $self->_appendRawDataToFile ($self->debugDir."processing.txt",$content."\n");
421             }
422              
423             1;
424             __END__