# $Id: //depot/prod/test/nacldev/lib/NACL/Exceptions/UnexpectedState.pm#1 $ # # Copyright (c) 2009-2012 NetApp Inc. # All rights reserved. # ## @summary Provide an exception class that is a subclass of ## NATE::BaseException that will be thrown when ## any of the monitoring field has reached an unexpected ## state when waiting for the STask operation to complete. ## ## ## @author isshwar@netapp.com, dl-nacl-dev@netapp.com ## @status Shared ## @pod here =head1 NAME NACL::Exceptions::UnexpectedState =head1 DESCRIPTION An exception to be thrown if any of the monitoring field has reached an unexpected state when waiting for the STask operation to complete. =head1 EXAMPLE # Example for catching the exception use NACL::Exceptions::UnexpectedState qw(:try); try { NACL::STask::Volume->create(%args); } catch NACL::Exceptions::UnexpectedState with { my $ex = shift; $Log->log("Operation failed!". $ex->text()); # Log the monitored information $Log->log($ex->get_monitored_info()); foreach my $field (@{$ex->monitoring_fields()}) { my $monitored_value = $ex->$field(); # May be invoke some handler with $field and $monitored_value .... } }; # Example for throwing exception use NACL::Exceptions::UnexpectedState qw(:try); NACL::Exceptions::UnexpectedState->throw("Unexpected state", monitoring_fields => ['state'], state => 'restricted'); =head1 ATTRIBUTES C<< "monitoring_fields" => \@monitoring_fields >> The list of field(s) which are monitored. If you pass a scalar value, then it would be stored as an array internally. Note that the fields specified in the 'monitoring_fields' option could be in its hyphenated or underscored format. This class handles both the variations for the accessor methods. Eg: try { NACL::Exceptions::UnexpectedState->throw("Unexpected state", monitoring_fields => ['create-time'], state => 'value'); } catch NACL::Exceptions::UnexpectedState with { my $ex = shift; $Log->log($ex->create_time()); # Underscored format works my $field = 'create-time'; $Log->log($ex->$field()); # Hyphenated format also works! }; C << "other_attributes" >> All the fields which are mentioned in the C can be the attributes of the exception object. =head1 METHODS =head2 get_monitored_info This method invoked on the exception object will return the monitored information at the time the exception was thrown. It returns a string in the following format: "$attr1 = $value1 , [$attr2 = $value2, ...] =head2 other_accessor_methods You can get the value of any of the attributes by invoking $ex->$attribute_name(). =cut package NACL::Exceptions::UnexpectedState; use base qw(NATE::BaseException); use Data::Dumper; use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); sub new { my $self = shift; my $obj = $self->SUPER::new(@_); $obj->init(@_); return $obj; } # To add the methods to the namespace on the fly sub init { my $self = shift; $Log->enter() if $may_enter; my ($text, %args) = @_; unless (defined $self->{monitoring_fields}) { $Log->warn('Internal warning: monitoring_fields is not specified'); $self->{monitoring_fields} = []; } $self->{monitoring_fields}=[$self->{monitoring_fields}] unless (ref $self->{monitoring_fields}); # Accessor methods need to be added for the fields specified in # monitoring_fields and 'monitoring_field' itself my @fields = (@{$self->{'monitoring_fields'}}, 'monitoring_fields'); foreach my $input (@fields) { # Add the accessor method to the symbol table. my $subroutine = sub { my ($obj, %args) = @_; $Log->exit() if $may_exit; NATE::BaseException->throw( "Setting the field '$input' in the exception object is ". "not allowed") if (scalar (keys %args)); return $obj->{$input}; }; *{ $input } = $subroutine; my $underscored_input = $input; $underscored_input =~ s/(-|\.)/_/g; $underscored_input =~ s/^(\d.*)/_$1/; *{ $underscored_input } = $subroutine; } # Check to see whether user specified attributes for creating the # exception object are those listed in monitoring_fields. foreach my $field (keys %args) { unless($self->can($field)) { $Log->warn("Internal warning: Field $field is not listed in ". "'monitoring_fields'. Hence it is considered to be an invalid". " field. Note that the accessor method would not be defined ". "for $field"); } } $Log->exit() if $may_exit; } # To get the monitored information when the exception was thrown. This method # could be used if the user is not bothered about the monitored fields but # just want to log the information sub get_monitored_info { my $self = shift; $Log->enter() if $may_enter; my $str = ''; foreach $field (@{$self->monitoring_fields()}) { # Somehow for fields which start with leading digit, I'm not able to # add the entry into symbol table. my $method = $field; $method =~ s/^(\d.*)/_$1/; my $value = defined ($self->$method())? $self->$method(): 'UNDEF'; $str .= "$field = ". $value . ", "; } $str =~ s/,\s$//; $Log->exit() if $may_exit; return $str; } 1;