File Coverage

lib/UR/ObjectDeprecated.pm
Criterion Covered Total %
statement 104 196 53.0
branch 39 96 40.6
condition 10 15 66.6
subroutine 18 29 62.0
pod 0 15 0.0
total 171 351 48.7


line stmt bran cond sub pod time code
1             package UR::Object;
2              
3             # deprecated parts of the UR::Object API
4              
5 266     266   1055 use warnings;
  266         367  
  266         7875  
6 266     266   969 use strict;
  266         340  
  266         8191  
7             require UR;
8             our $VERSION = "0.46"; # UR $VERSION;
9              
10 266     266   957 use Data::Dumper;
  266         341  
  266         11643  
11 266     266   1015 use Scalar::Util qw(blessed);
  266         334  
  266         56877  
12              
13             sub get_with_special_parameters {
14             # When overridden, this allows a class to take non-properties as parameters
15             # to get(), and handle loading in a special way. Ideally this is handled by
16             # a custom data source, or properties with smart definitions.
17 1     1 0 2 my $class = shift;
18 1         3 my $rule = shift;
19 1         12 Carp::confess(
20             "Unknown parameters to $class get(). "
21             . "Implement get_with_special_parameters() to handle non-standard"
22             . " (non-property) query options.\n"
23             . "The special params were "
24             . Dumper(\@_)
25             . "Rule ID: " . $rule->id . "\n"
26             );
27             }
28              
29             sub get_or_create {
30 30     30 0 65 my $self = shift;
31 30   66     121 return $self->get( @_ ) || $self->create( @_ );
32             }
33              
34             sub set {
35 0     0 0 0 my $self = shift;
36 0         0 my @rvals;
37              
38 0         0 while (@_) {
39 0         0 my $property_name = shift;
40 0         0 my $value = shift;
41 0         0 push(@rvals, $self->$property_name($value));
42             }
43              
44 0 0       0 if(wantarray) {
45 0         0 return @rvals;
46             }
47             else {
48 0         0 return \@rvals;
49             }
50             }
51              
52             sub property_diff {
53             # Ret hashref of the differences between the object and some other object.
54             # The "other object" may be a hashref or hash, in which case it will
55             # treat each key as a property.
56              
57 44     44 0 96 my ($self, $other) = @_;
58 44         84 my $diff = {};
59              
60             # If we got a hash instead of a hashref...
61 44 50       162 if (@_ > 2)
62             {
63 0         0 shift;
64 0         0 $other = { @_ }
65             }
66              
67 266     266   1233 no warnings;
  266         345  
  266         300827  
68 44         61 my $self_value;
69             my $other_value;
70 44         128 my $class_object = $self->__meta__;
71 44         470 for my $property ($class_object->all_property_names)
72             {
73 237 50       346 if (ref($other) eq 'HASH')
74             {
75 237 100       399 next unless exists $other->{$property};
76 187         233 $other_value = $other->{$property};
77             }
78             else
79             {
80 0         0 $other_value = $other->$property;
81             }
82 187         507 $self_value = $self->$property;
83 187 100       458 $diff->{$property} = $self_value if ($other_value ne $self_value);
84             }
85 44         150 return $diff;
86             }
87              
88             # TODO: make this a context operation
89             sub unload {
90 2184     2184 0 391086 my $proto = shift;
91              
92 2184 100       4355 return unless ($proto->class->__meta__->is_uncachable);
93              
94 2172         2147 my ($self, $class);
95 2172 100       3278 ref $proto ? $self = $proto : $class = $proto;
96            
97 2172         1840 my $cx = $UR::Context::current;
98              
99 2172 100       2863 if ( $self ) {
100             # object method
101              
102             # The only things which can be unloaded are things committed to
103             # their database in the exact same state. Everything else must
104             # be reverted or deleted.
105 1604 100       2742 return unless $self->{db_committed};
106 1585 100       2911 if ($self->__changes__) {
107             #warn "NOT UNLOADING CHANGED OBJECT! $self $self->{id}\n";
108 3         6 return;
109             }
110              
111 1582         2771 $self->__signal_change__('unload');
112 1582 50       3002 if ($ENV{'UR_DEBUG_OBJECT_RELEASE'}) {
113 0         0 print STDERR "MEM UNLOAD object $self class ",$self->class," id ",$self->id,"\n";
114             }
115 1582         3402 $cx->_abandon_object($self);
116 1582         2543 return $self;
117             }
118             else {
119             # class method
120              
121             # unload the objects in the class
122             # where there are subclasses of the class
123             # delegate to them
124              
125 568         597 my @unloaded;
126              
127             # unload all objects of this class
128 568         1016 my @involved_classes = ( $class );
129 568         1834 for my $obj ($cx->all_objects_loaded_unsubclassed($class))
130             {
131 1133         1734 push @unloaded, $obj->unload;
132             }
133              
134             # unload any objects that belong to any subclasses
135 568         1871 for my $subclass ($cx->__meta__->subclasses_loaded($class))
136             {
137 0         0 push @involved_classes, $subclass;
138 0         0 push @unloaded, $subclass->unload;
139             }
140              
141             # get rid of the loading info matching this class
142 568         1239 foreach my $template_id ( keys %$UR::Context::all_params_loaded ) {
143 1442 100       3286 if (UR::BoolExpr::Template->get($template_id)->subject_class_name->isa($class)) {
144 808         1808 delete $UR::Context::all_params_loaded->{$template_id};
145             }
146             }
147              
148             # Turn off the all_objects_are_loaded flags
149 568         919 delete @$UR::Context::all_objects_are_loaded{@involved_classes};
150              
151 568         1821 return @unloaded;
152             }
153             }
154              
155             # TODO: replace internal calls to go right to the context method
156             sub is_loaded {
157             # this is just here for backward compatability for external calls
158             # get() now goes to the context for data
159            
160             # This shortcut handles the most common case rapidly.
161             # A single ID is passed-in, and the class name used is
162             # not a super class of the specified object.
163             # This logic is in both get() and is_loaded().
164              
165 62926     62926 0 71455 my $quit_early = 0;
166 62926 100 100     145728 if ( @_ == 2 && !ref($_[1]) ) {
167 1876 50       4162 unless (defined($_[1])) {
168 0         0 Carp::confess();
169             }
170 1876         4248 my $obj = $UR::Context::all_objects_loaded->{$_[0]}->{$_[1]};
171 1876 100       4475 return $obj if $obj;
172             # we could safely return nothing right now, except
173             # that a subclass of this type may have the object
174 1568 100       5613 return unless $_[0]->__meta__->subclasses_loaded; # nope, there were no subclasses
175             }
176              
177 61866         61262 my $class = shift;
178 61866         168649 my $rule = UR::BoolExpr->resolve_normalized($class,@_);
179 61866         185764 return $UR::Context::current->get_objects_for_class_and_rule($class,$rule,0);
180             }
181              
182             sub subclasses_loaded {
183 0     0 0 0 return shift->__meta__->subclasses_loaded();
184             }
185              
186             # THESE SHOULD PROBABLY GO ON THE CLASS META
187              
188             sub all_objects_are_loaded {
189             # Keep track of which classes claim that they are completely loaded, and that no more loading should be done.
190             # Classes which have the above function return true should set this after actually loading everything.
191             # This class will do just that if it has to load everything itself.
192              
193 2150     2150 0 3027 my $class = shift;
194             #$meta = $class->__meta__;
195 2150 100       7758 if (@_) {
    100          
196             # Setting the attribute
197 290         601 $UR::Context::all_objects_are_loaded->{$class} = shift;
198             } elsif (! exists $UR::Context::all_objects_are_loaded->{$class}) {
199             # unknown... ask the parent classes and remember the answer
200 1847         49042 foreach my $parent_class ( $class->inheritance ) {
201 5842 100       9773 if (exists $UR::Context::all_objects_are_loaded->{$parent_class}) {
202 1         2 $UR::Context::all_objects_are_loaded->{$class} = $UR::Context::all_objects_are_loaded->{$parent_class};
203 1         1 last;
204             }
205             }
206             }
207 2150         6562 return $UR::Context::all_objects_are_loaded->{$class};
208             }
209              
210              
211             # Observer pattern (old)
212              
213             sub create_subscription {
214 149     149 0 5981 my $self = shift;
215 149         510 my %params = @_;
216              
217             # parse parameters
218 149         214 my ($class,$id,$method,$callback,$note,$priority);
219              
220 149         607 my %translate = (
221             method => 'aspect',
222             id => 'subject_id',
223             );
224 149         434 my @param_names = qw(method callback note priority id);
225 149         182 my %observer_params;
226 149         305 for my $name (@param_names) {
227 745 100       1303 if (exists $params{$name}) {
228 303   66     1083 my $obs_name = $translate{$name} || $name;
229 303         563 $observer_params{$obs_name} = delete $params{$name};
230             }
231             }
232              
233 149         604 $observer_params{'subject_class_name'} = $self->class;
234 149 100 100     1087 if (!defined $observer_params{'subject_id'} and ref($self)) {
235 48         116 $observer_params{'subject_id'} = $self->id;
236             }
237              
238 149 50       575 if (my @unknown = keys %params) {
239 0         0 Carp::croak "Unknown options @unknown passed to create_subscription!";
240             }
241              
242             # validate
243 149 50       414 if (my @bad_params = %params) {
244 0         0 Carp::croak "Bad params passed to add_listener: @bad_params";
245             }
246              
247 149         1060 my $observer = UR::Observer->create(%observer_params);
248 149 50       431 return unless $observer;
249 149         1382 return [@observer_params{'subject_class_name','subject_id','aspect','callback','note'}];
250             }
251              
252              
253             sub validate_subscription
254             {
255             # Everything is invalid unless you make it valid by implementing
256             # validate_subscription on your class. (Or use the new API.)
257 1     1 0 3 return;
258             }
259              
260              
261             sub inform_subscription_cancellation
262             {
263             # This can be overridden in derived classes if the class wants to know
264             # when subscriptions are cancelled.
265 17     17 0 63 return 1;
266             }
267              
268              
269             sub cancel_change_subscription ($@)
270             {
271 0     0 0 0 my ($class,$id,$property,$callback,$note);
272              
273 0 0 0     0 if (@_ >= 4)
    0          
274             {
275 0         0 ($class,$id,$property,$callback,$note) = @_;
276 0 0       0 die "Bad parameters." if ref($class);
277             }
278             elsif ( (@_==3) or (@_==2) )
279             {
280 0         0 ($class, $property, $callback) = @_;
281 0 0       0 if (ref($_[0]))
282             {
283 0         0 $class = ref($_[0]);
284 0         0 $id = $_[0]->id;
285             }
286             }
287             else
288             {
289 0         0 die "Bad parameters.";
290             }
291              
292 0         0 my %params;
293 0 0       0 if (defined $class) {
294 0         0 $params{'subject_class_name'} = $class;
295             }
296 0 0       0 if (defined $id) {
297 0         0 $params{'subject_id'} = $id;
298             }
299 0 0       0 if (defined $property) {
300 0         0 $params{'aspect'} = $property;
301             }
302 0 0       0 if (defined $callback) {
303 0         0 $params{'callback'} = $callback;
304             }
305 0 0       0 if (defined $note) {
306 0         0 $params{'note'} = $note;
307             }
308              
309 0         0 my @observers = UR::Observer->get(%params);
310 0 0       0 return unless @observers;
311 0 0       0 if (@observers > 1) {
312             Carp::croak('Matched more than one observer within cancel_change_subscription(). Params were: '
313 0         0 . join(', ', map { "$_ => " . $params{$_} } keys %params));
  0         0  
314             }
315 0         0 $observers[0]->delete();
316             }
317              
318             # This should go away when we shift to fully to a transaction log for deletions.
319              
320             sub ghost_class {
321 8031     8031 0 25210 my $class = $_[0]->class;
322 8031         15622 $class = $class . '::Ghost';
323 8031         19749 return $class;
324             }
325              
326              
327             package UR::ModuleBase;
328             # Method for setting a callback using the old, non-command messaging API
329              
330             =pod
331              
332             =over 4
333              
334             =item message_callback
335              
336             $sub_ref = UR::ModuleBase->message_callback($type);
337             UR::ModuleBase->message_callback($type, $sub_ref);
338              
339             This method returns and optionally sets the subroutine that handles
340             messages of a specific type.
341              
342             =back
343              
344             =cut
345              
346             ## set or return a callback that has been created for a message type
347             sub message_callback
348             {
349 0     0 0   my $self = shift;
350 0           my ($type, $callback) = @_;
351              
352 0           my $methodname = $type . '_messages_callback';
353              
354 0 0         if (!$callback) {
355             # to clear the old, deprecated non-command messaging API callback
356 0           return UR::Object->$methodname($callback);
357             }
358              
359             my $wrapper_callback = sub {
360 0     0     my($obj,$msg) = @_;
361              
362 0           my $obj_class = $obj->class;
363 0 0         my $obj_id = (ref($obj) ? ($obj->can("id") ? $obj->id : $obj) : $obj);
    0          
364              
365 0           my $message_package = $type . '_package';
366 0 0         my $message_object = UR::ModuleBase::Message->create
367             (
368             text => $msg,
369             level => 1,
370             package_name => $obj->$message_package(),
371             call_stack => ($type eq "error" ? _current_call_stack() : []),
372             time_stamp => time,
373             type => $type,
374             owner_class => $obj_class,
375             owner_id => $obj_id,
376             );
377 0           $callback->($message_object, $obj, $type);
378 0           $_[1] = $message_object->text;
379 0           };
380              
381             # To support the old, deprecated, non-command messaging API
382 0           UR::Object->$methodname($wrapper_callback);
383             }
384              
385             sub message_object
386             {
387 0     0 0   my $self = shift;
388             # see how we were called
389 0 0         if (@_ < 2)
390             {
391 266     266   1405 no strict 'refs';
  266         407  
  266         43636  
392             # return the message object
393 0           my ($type) = @_;
394 0           my $method = $type . '_message';
395 0           my $msg_text = $self->method();
396 0           my $obj_class = $self->class;
397 0 0         my $obj_id = (ref($self) ? ($self->can("id") ? $self->id : $self) : $self);
    0          
398 0           my $msgdata = $self->_get_msgdata();
399             return UR::ModuleBase::Message->create
400             (
401             text => $msg_text,
402             level => 1,
403 0 0         package_name => $msgdata->{$type . '_package'},
404             call_stack => ($type eq "error" ? _current_call_stack() : []),
405             time_stamp => time,
406             type => $type,
407             owner_class => $obj_class,
408             owner_id => $obj_id,
409             );
410             }
411             }
412              
413             foreach my $type ( UR::ModuleBase->message_types ) {
414             my $retriever_name = $type . '_text';
415             my $compat_name = $type . '_message';
416             my $sub = sub {
417 0     0     my $self = shift;
418 0           return $self->$compat_name();
419             };
420              
421 266     266   1153 no strict 'refs';
  266         344  
  266         11913  
422             *$retriever_name = $sub;
423             }
424              
425              
426             # class that stores and manages messages for the deprecated API
427             package UR::ModuleBase::Message;
428              
429 266     266   1031 use Scalar::Util qw(weaken);
  266         444  
  266         82565  
430              
431             ##- use UR::Util;
432             UR::Util->generate_readonly_methods
433             (
434             text => undef,
435             level => undef,
436             package_name => undef,
437             call_stack => [],
438             time_stamp => undef,
439             owner_class => undef,
440             owner_id => undef,
441             type => undef,
442             );
443              
444             sub create
445             {
446 0     0     my $class = shift;
447 0           my $obj = {@_};
448 0           bless ($obj,$class);
449 0 0         weaken $obj->{'owner_id'} if (ref($obj->{'owner_id'}));
450              
451 0           return $obj;
452             }
453              
454             sub owner
455             {
456 0     0     my $self = shift;
457 0           my ($owner_class,$owner_id) = ($self->owner_class, $self->owner_id);
458 0 0         if (not defined($owner_id))
    0          
459             {
460 0           return $owner_class;
461             }
462             elsif (ref($owner_id))
463             {
464 0           return $owner_id;
465             }
466             else
467             {
468 0           return $owner_class->get($owner_id);
469             }
470             }
471              
472             sub string
473             {
474 0     0     my $self = shift;
475 0           "$self->{time_stamp} $self->{type}: $self->{text}\n";
476             }
477              
478             sub _stack_item_params
479             {
480 0     0     my ($self, $stack_item) = @_;
481 0           my ($function, $parameters, @parameters);
482              
483 0 0         return unless ($stack_item =~ s/\) called at [^\)]+ line [^\)]+\s*$/\)/);
484              
485 0 0         if ($stack_item =~ /^\s*([^\(]*)(.*)$/)
486             {
487 0           $function = $1;
488 0           $parameters = $2;
489 0           @parameters = eval $parameters;
490 0           return ($function, @parameters);
491             }
492             else
493             {
494 0           return;
495             }
496             }
497              
498             package UR::Object;
499              
500              
501             1;
502              
503