File Coverage

lib/App/Session.pm
Criterion Covered Total %
statement 97 180 53.8
branch 53 136 38.9
condition 9 27 33.3
subroutine 8 15 53.3
pod 9 10 90.0
total 176 368 47.8


line stmt bran cond sub pod time code
1              
2             #############################################################################
3             ## $Id: Session.pm 3666 2006-03-11 20:34:10Z spadkins $
4             #############################################################################
5              
6             package App::Session;
7             $VERSION = (q$Revision: 3666 $ =~ /(\d[\d\.]*)/)[0]; # VERSION numbers generated by svn
8              
9 6     6   33 use App;
  6         10  
  6         202  
10 6     6   32 use App::Reference;
  6         16  
  6         119  
11              
12 6     6   32 use strict;
  6         10  
  6         14668  
13              
14             =head1 NAME
15              
16             App::Session - represents a sequence of multiple events
17             perhaps executed in separate processes
18              
19             =head1 SYNOPSIS
20              
21             # ... official way to get a Session object ...
22             use App;
23             $session = App->context();
24             $context = $session->session(); # get the session
25              
26             # any of the following named parameters may be specified
27             $session = $context->session(
28             );
29              
30             # ... alternative way (used internally) ...
31             use App::Session;
32             $session = App::Session->new();
33              
34             =cut
35              
36             #############################################################################
37             # CONSTANTS
38             #############################################################################
39              
40             =head1 DESCRIPTION
41              
42             A Session class models the sequence of events associated with a
43             use of the system. These events may occur in different processes.
44              
45             For instance, in a web environment, when a new user arrives at a web site,
46             he is allocated a new
47             Session, even though he may not even be authenticated. In subsequent
48             requests, his actions are tied together by a Session ID that is transmitted
49             from the browser to the server on each request. During the Session, he
50             may log in, log out, and log in again.
51             Finally, Sessions in the web environment generally time out if not
52             accessed for a certain period of time.
53              
54             Conceptually, the Session may span processes, so they generally have a
55             way to persist themselves so that they may be reinstantiated wherever
56             they are needed. This would certainly be true in CGI or Cmd Contexts
57             where each CGI request or command execution relies on and contributes
58             to the running state accumulated in the Session. Other execution
59             Contexts (Curses, Gtk) only require trivial implementations of a Session
60             because it stays in memory for the duration of the process.
61             Nonetheless, even these Contexts use a Session object so that the
62             programming model across multiple platforms is the same.
63              
64             =cut
65              
66             #############################################################################
67             # CLASS GROUP
68             #############################################################################
69              
70             =head1 Class Group: Session
71              
72             The following classes might be a part of the Session Class Group.
73              
74             =over
75              
76             =item * Class: App::Session
77              
78             =item * Class: App::Session::HTMLHidden
79              
80             =item * Class: App::Session::Cookie
81              
82             =item * Class: App::Session::ApacheSession
83              
84             =item * Class: App::Session::ApacheSessionX
85              
86             =back
87              
88             =cut
89              
90             #############################################################################
91             # CONSTRUCTOR METHODS
92             #############################################################################
93              
94             =head1 Constructor Methods:
95              
96             =cut
97              
98             #############################################################################
99             # new()
100             #############################################################################
101              
102             =head2 new()
103              
104             This constructor is used to create Session objects.
105             Customized behavior for a particular type of Sessions
106             is achieved by overriding the _init() method.
107              
108             * Signature: $session = App::Session->new($array_ref)
109             * Signature: $session = App::Session->new($hash_ref)
110             * Signature: $session = App::Session->new("array",@args)
111             * Signature: $session = App::Session->new(%named)
112             * Param: $array_ref []
113             * Param: $hash_ref {}
114             * Return: $session App::Session
115             * Throws: App::Exception
116             * Since: 0.01
117              
118             Sample Usage:
119              
120             use "App::Session";
121              
122             $ref = App::Session->new("array", "x", 1, -5.4, { pi => 3.1416 });
123             $ref = App::Session->new( [ "x", 1, -5.4 ] );
124             $ref = App::Session->new(
125             arg1 => 'value1',
126             arg2 => 'value2',
127             );
128              
129             =cut
130              
131             sub new {
132 6 50   6 1 23 &App::sub_entry if ($App::trace);
133 6         14 my $this = shift;
134 6   33     40 my $class = ref($this) || $this;
135              
136 6         12 my $self = {};
137 6         16 bless $self, $class;
138              
139 6         24 $self->_init(@_); # allows a subclass to override this portion
140              
141 6 50       17 &App::sub_exit($self) if ($App::trace);
142 6         17 return $self;
143             }
144              
145             =cut
146              
147             #############################################################################
148             # _init()
149             #############################################################################
150              
151             =head2 _init()
152              
153             The _init() method is called from within the standard Session constructor.
154             The _init() method in this class does nothing.
155             It allows subclasses of the Session to customize the behavior of the
156             constructor by overriding the _init() method.
157              
158             * Signature: _init($named)
159             * Param: $named {} [in]
160             * Return: void
161             * Throws: App::Exception
162             * Since: 0.01
163              
164             Sample Usage:
165              
166             $ref->_init($args);
167              
168             =cut
169              
170             sub _init {
171 5 50   5   21 &App::sub_entry if ($App::trace);
172 5         9 my $self = shift;
173 5 50       17 &App::sub_exit() if ($App::trace);
174             }
175              
176             #############################################################################
177             # PUBLIC METHODS
178             #############################################################################
179              
180             =head1 Public Methods:
181              
182             =cut
183              
184             #############################################################################
185             # get()
186             #############################################################################
187              
188             =head2 get()
189              
190             The get() returns the var of a session_object.
191              
192             * Signature: $value = $session->get($service_name_var);
193             * Signature: $value = $session->get($service, $name, $var);
194             * Signature: $value = $session->get($service, $name, $var, $default);
195             * Signature: $value = $session->get($service, $name, $var, $default, $setdefault);
196             * Param: $service string
197             * Param: $name string
198             * Param: $attribute string
199             * Param: $default any
200             * Param: $setdefault boolean
201             * Return: $value string,ref
202             * Throws:
203             * Since: 0.01
204              
205             Sample Usage:
206              
207             $cname = $session->get("cname");
208             $cname = $session->get("default.cname");
209             $cname = $session->get("SessionObject.default.cname");
210             $cname = $session->get("SessionObject", "default", "cname");
211             $width = $session->get("SessionObject", "main.app.toolbar.calc", "width", 45, 1);
212             $width = $session->get("main.app.toolbar.calc.width", undef, undef, 45, 1);
213              
214             =cut
215              
216             sub get {
217 22 50   22 1 64 &App::sub_entry if ($App::trace);
218 22         43 my ($self, $service, $name, $var, $default, $setdefault) = @_;
219 22 100       40 if (!defined $name) {
220 16 100       55 if ($service =~ /^([A-Z][^.]*)\.(.+)/) {
221 6         13 $service = $1;
222 6         12 $name = $2;
223             }
224             else {
225 10         11 $name = $service;
226 10         15 $service = "SessionObject";
227             }
228 16 100       128 if ($name =~ /^([a-zA-Z0-9_\.-]+)([\{\}\[\]].*)$/) {
    100          
229 2         5 $name = $1;
230 2         4 $var = $2;
231             }
232             elsif ($name =~ /^([a-zA-Z0-9_\.-]+)\.([a-zA-Z0-9_]+)$/) {
233 8         16 $name = $1;
234 8         13 $var = $2;
235             }
236             else {
237 6         7 $var = $name;
238 6         8 $name = "default";
239             }
240             }
241              
242 22         21 my ($perl, $value);
243              
244 22 100       67 if ($var !~ /[\[\]\{\}]/) { # no special chars, "foo.bar"
    100          
    50          
245 18         43 $value = $self->{cache}{$service}{$name}{$var};
246 18 100 100     59 if (!defined $value && defined $default) {
247 5         7 $value = $default;
248 5 100       13 if ($setdefault) {
249 1         4 $self->{store}{$service}{$name}{$var} = $value;
250 1 50       6 $self->{context}->service($service, $name) if (!defined $self->{cache}{$service}{$name});
251 1         3 $self->{cache}{$service}{$name}{$var} = $value;
252             }
253             }
254 18 50 33     40 $self->dbgprint("Session->get($service,$name,$var) (value) = [$value]")
255             if ($App::DEBUG && $self->dbg(3));
256 18         103 return $value;
257             } # match {
258             elsif ($var =~ /^\{([^\}]+)\}$/) { # a simple "{foo.bar}"
259 2         6 $var = $1;
260 2         6 $value = $self->{cache}{$service}{$name}{$var};
261 2 50 33     9 if (!defined $value && defined $default) {
262 0         0 $value = $default;
263 0 0       0 if ($setdefault) {
264 0         0 $self->{store}{$service}{$name}{$var} = $value;
265 0 0       0 $self->{context}->service($service, $name) if (!defined $self->{cache}{$service}{$name});
266 0         0 $self->{cache}{$service}{$name}{$var} = $value;
267             }
268             }
269 2 50 33     7 $self->dbgprint("Session->get($service,$name,$var) (value) = [$value]")
270             if ($App::DEBUG && $self->dbg(3));
271 2         9 return $value;
272             } # match {
273             elsif ($var =~ /^[\{\}\[\]].*$/) {
274              
275 2 100       23 $self->{context}->service($service, $name) if (!defined $self->{cache}{$service}{$name});
276              
277 2         19 $var =~ s/\{([^\}]+)\}/\{"$1"\}/g;
278 2         7 $perl = "\$value = \$self->{cache}{\$service}{\$name}$var;";
279 2         114 eval $perl;
280 2 50       11 $self->add_message("eval [$perl]: $@") if ($@);
281 2 50 33     9 $self->dbgprint("Session->get($service,$name,$var) (indexed) = [$value]")
282             if ($App::DEBUG && $self->dbg(3));
283             }
284              
285 2 50       6 &App::sub_exit($value) if ($App::trace);
286 2         16 return $value;
287             }
288              
289             #############################################################################
290             # set()
291             #############################################################################
292              
293             =head2 set()
294              
295             The set() sets the value of a variable in one of the Services for the Session.
296              
297             * Signature: $session->set($service_name_var, $value);
298             * Signature: $session->set($service, $name, $var, $value);
299             * Param: $service_name_var string
300             * Param: $service string
301             * Param: $name string
302             * Param: $var string
303             * Param: $value string,ref
304             * Return: void
305             * Throws:
306             * Since: 0.01
307              
308             Sample Usage:
309              
310             $session->set("cname", "main_screen");
311             $session->set("default.cname", "main_screen");
312             $session->set("SessionObject.default.cname", "main_screen");
313             $session->set("SessionObject", "default", "cname", "main_screen");
314             $session->set("SessionObject", "main.app.toolbar.calc", "width", 50);
315             $session->set("SessionObject", "xyz", "{arr}[1][2]", 14);
316             $session->set("SessionObject", "xyz", "{arr.totals}", 14);
317              
318             =cut
319              
320             sub set {
321 11 50   11 1 1109 &App::sub_entry if ($App::trace);
322 11         22 my ($self, $service, $name, $var, $value) = @_;
323 11 100       23 if (!defined $value) {
324 4         5 $value = $name;
325 4         8 $name = undef;
326             }
327 11 100       23 if (!defined $name) {
328 7 100       29 if ($service =~ /^([A-Z][^.]*)\.(.+)/) {
329 4         12 $service = $1;
330 4         7 $name = $2;
331             }
332             else {
333 3         5 $name = $service;
334 3         6 $service = "SessionObject";
335             }
336 7 100       37 if ($name =~ /^([a-zA-Z0-9_\.-]+)([\{\}\[\]].*)$/) {
    100          
337 2         4 $name = $1;
338 2         5 $var = $2;
339             }
340             elsif ($name =~ /^([a-zA-Z0-9_\.-]+)\.([a-zA-Z0-9_]+)$/) {
341 3         8 $name = $1;
342 3         5 $var = $2;
343             }
344             else {
345 2         4 $var = $name;
346 2         4 $name = "default";
347             }
348             }
349              
350 11 50       139 if ($value eq "{:delete:}") {
351 0         0 return $self->delete($service,$name,$var);
352             }
353              
354 11         7 my ($perl);
355 11 50 33     28 $self->dbgprint("Session->set($name,$var,$value)")
356             if ($App::DEBUG && $self->dbg(3));
357              
358 11 100       48 if ($var !~ /[\[\]\{\}]/) { # no special chars, "foo.bar"
    100          
    50          
359 7         27 $self->{store}{$service}{$name}{$var} = $value;
360 7         18 $self->{cache}{$service}{$name}{$var} = $value;
361 7         16 return;
362             } # match {
363             elsif ($var =~ /^\{([^\}]+)\}$/) { # a simple "{foo.bar}"
364 2         8 $var = $1;
365 2         7 $self->{store}{$service}{$name}{$var} = $value;
366 2         6 $self->{cache}{$service}{$name}{$var} = $value;
367 2         5 return;
368             }
369             elsif ($var =~ /^\{/) { # i.e. "{columnSelected}{first_name}"
370              
371 2         20 $var =~ s/\{([^\}]+)\}/\{"$1"\}/g; # put quotes around hash keys
372              
373 2         8 $perl = "\$self->{store}{$service}{\$name}$var = \$value;";
374 2 100       13 $perl .= "\$self->{cache}{$service}{\$name}$var = \$value;"
375             if (defined $self->{cache}{$service}{$name});
376              
377 2         151 eval $perl;
378 2 50       12 $self->add_message("eval [$perl]: $@") if ($@);
379             }
380              
381 2 50       11 &App::sub_exit() if ($App::trace);
382             }
383              
384             #############################################################################
385             # default()
386             #############################################################################
387              
388             =head2 default()
389              
390             The default() sets the value of a SessionObject's attribute
391             only if it is currently undefined.
392              
393             * Signature: $session->default($service_name_var, $value);
394             * Signature: $session->default($service, $name, $var, $value);
395             * Param: $service_name_var string
396             * Param: $service string
397             * Param: $name string
398             * Param: $var string
399             * Param: $value string,ref
400             * Return: $value string,ref
401             * Throws:
402             * Since: 0.01
403              
404             Sample Usage:
405              
406             $cname = $session->default("default", "cname");
407             $width = $session->default("main.app.toolbar.calc", "width");
408              
409             =cut
410              
411             sub default {
412 0 0   0 1   &App::sub_entry if ($App::trace);
413 0           my ($self, $service, $name, $var, $value) = @_;
414 0           $self->get($service, $name, $var, $value, 1);
415 0 0         &App::sub_exit() if ($App::trace);
416             }
417              
418             #############################################################################
419             # delete()
420             #############################################################################
421              
422             =head2 delete()
423              
424             The delete() deletes an attribute of a session_object in the Session.
425              
426             * Signature: $session->delete($service, $name, $attribute);
427             * Param: $service string
428             * Param: $name string
429             * Param: $attribute string
430             * Return: void
431             * Throws:
432             * Since: 0.01
433              
434             Sample Usage:
435              
436             $session->delete("default", "cname");
437             $session->delete("main.app.toolbar.calc", "width");
438             $session->delete("xyz", "{arr}[1][2]");
439             $session->delete("xyz", "{arr.totals}");
440              
441             =cut
442              
443             sub delete {
444 0 0   0 1   &App::sub_entry if ($App::trace);
445 0           my ($self, $service, $name, $var) = @_;
446 0 0         if (!defined $name) {
447 0 0         if ($service =~ /^([A-Z][^.]*)\.(.+)/) {
448 0           $service = $1;
449 0           $name = $2;
450             }
451             else {
452 0           $name = $service;
453 0           $service = "SessionObject";
454             }
455 0 0         if ($name =~ /^([a-zA-Z0-9_\.-]+)([\{\}\[\]].*)$/) {
    0          
456 0           $name = $1;
457 0           $var = $2;
458             }
459             elsif ($name =~ /^([a-zA-Z0-9_\.-]+)\.([a-zA-Z0-9_]+)$/) {
460 0           $name = $1;
461 0           $var = $2;
462             }
463             else {
464 0           $var = $name;
465 0           $name = "default";
466             }
467             }
468              
469 0           my ($perl);
470              
471 0 0 0       $self->dbgprint("Session->delete($name,$var)")
472             if ($App::DEBUG && $self->dbg(3));
473              
474 0 0 0       if (!defined $var || $var eq "") {
475 0 0         if ($name =~ /^([a-zA-Z0-9_\.-]+)([\{\}\[\]].*)$/) {
    0          
476 0           $name = $1;
477 0           $var = $2;
478             }
479             elsif ($name =~ /^([a-zA-Z0-9_\.-]+)\.([a-zA-Z0-9_]+)$/) {
480 0           $name = $1;
481 0           $var = $2;
482             }
483             else {
484 0           $var = $name;
485 0           $name = "default";
486             }
487             }
488              
489 0 0         if ($var !~ /[\[\]\{\}]/) { # no special chars, "foo.bar"
    0          
    0          
490 0           delete $self->{store}{$service}{$name}{$var};
491 0 0         delete $self->{cache}{$service}{$name}{$var}
492             if (defined $self->{cache}{$service}{$name});
493 0           return;
494             } # match {
495             elsif ($var =~ /^\{([^\}]+)\}$/) { # a simple "{foo.bar}"
496 0           $var = $1;
497 0           delete $self->{store}{$service}{$name}{$var};
498 0 0         delete $self->{cache}{$service}{$name}{$var}
499             if (defined $self->{cache}{$service}{$name});
500 0           return;
501             }
502             elsif ($var =~ /^\{/) { # { i.e. "{columnSelected}{first_name}"
503              
504 0           $var =~ s/\{([^\}]+)\}/\{"$1"\}/g; # put quotes around hash keys
505              
506 0           $perl = "delete \$self->{store}{$service}{\$name}$var;";
507 0 0         $perl .= "delete \$self->{cache}{$service}{\$name}$var;"
508             if (defined $self->{cache}{$service}{$name});
509              
510 0           eval $perl;
511 0 0         $self->add_message("eval [$perl]: $@") if ($@);
512             #die "ERROR: Session->delete($name,$var): eval ($perl): $@" if ($@);
513             }
514             # } else we do nothing with it!
515 0 0         &App::sub_exit() if ($App::trace);
516             }
517              
518             #############################################################################
519             # get_session_id()
520             #############################################################################
521              
522             =head2 get_session_id()
523              
524             The get_session_id() returns the session_id of this particular session.
525             This session_id is unique for all time. If a session_id does not yet
526             exist, one will be created. The session_id is only created when first
527             requested, and not when the session is instantiated.
528              
529             * Signature: $session_id = $session->get_session_id();
530             * Param: void
531             * Return: $session_id string
532             * Throws:
533             * Since: 0.01
534              
535             Sample Usage:
536              
537             $session->get_session_id();
538              
539             =cut
540              
541             sub get_session_id {
542 0 0   0 1   &App::sub_entry if ($App::trace);
543 0           my $self = shift;
544 0           my $session_id = $self->{session_id};
545 0 0         if (!$session_id) {
546 0           $session_id = $self->new_session_id();
547 0           $self->{session_id} = $session_id;
548             }
549 0 0         &App::sub_exit($session_id) if ($App::trace);
550 0           $session_id;
551             }
552              
553             #############################################################################
554             # new_session_id()
555             #############################################################################
556              
557             =head2 new_session_id()
558              
559             The new_session_id() returns a new, unique session_id.
560              
561             * Signature: $session_id = $session->new_session_id();
562             * Param: void
563             * Return: $session_id string
564             * Throws:
565             * Since: 0.01
566              
567             Sample Usage:
568              
569             $session_id = $session->new_session_id();
570              
571             =cut
572              
573             my $seq = 0;
574              
575             sub new_session_id {
576 0 0   0 1   &App::sub_entry if ($App::trace);
577 0           my $self = shift;
578 0           my ($session_id);
579 0           $seq++;
580 0           $session_id = time() . ":" . $$;
581 0 0         $session_id .= ":$seq" if ($seq > 1);
582 0 0         &App::sub_exit($session_id) if ($App::trace);
583 0           $session_id;
584             }
585              
586             #############################################################################
587             # html()
588             #############################################################################
589              
590             =head2 html()
591              
592             The html() method ...
593              
594             * Signature: $html = $session->html();
595             * Param: void
596             * Return: $html string
597             * Throws:
598             * Since: 0.01
599              
600             Sample Usage:
601              
602             $session->html();
603              
604             The html() method on a session may be used by Contexts which embed session
605             information in a web page being returned to the user's browser.
606             (Some contexts do not use HTML for the User Interface and will not call
607             this routine.)
608              
609             The most common method of embedding the session information in the HTML
610             is to encode the session_id in an HTML hidden variable ().
611             That is what this implementation does.
612              
613             =cut
614              
615             sub html {
616 0 0   0 1   &App::sub_entry if ($App::trace);
617 0           my ($self, $options) = @_;
618 0           my ($session_id, $html);
619 0           $session_id = $self->get_session_id();
620 0           $html = "";
621 0 0         &App::sub_exit($html) if ($App::trace);
622 0           $html;
623             }
624              
625             #############################################################################
626             # dump()
627             #############################################################################
628              
629             =head2 dump()
630              
631             * Signature: $perl = $session->dump();
632             * Param: void
633             * Return: $perl text
634             * Throws: App::Exception
635             * Since: 0.01
636              
637             Sample Usage:
638              
639             $session = $context->session();
640             print $session->dump(), "\n";
641              
642             =cut
643              
644 6     6   46 use Data::Dumper;
  6         9  
  6         1198  
645              
646             sub dump {
647 0 0   0 1   &App::sub_entry if ($App::trace);
648 0           my ($self, $ref) = @_;
649 0 0         $ref = $self if (!$ref);
650 0           my %copy = %$ref;
651 0           delete $copy{context}; # don't dump the reference to the context itself
652 0           my $d = Data::Dumper->new([ \%copy ], [ "session" ]);
653 0           $d->Indent(1);
654 0 0         &App::sub_exit($d->Dump()) if ($App::trace);
655 0           return $d->Dump();
656             }
657              
658             sub print {
659 0     0 0   my $self = shift;
660 0           print $self->dump(@_);
661             }
662              
663             1;
664