sub _automethod : Automethod()

in managementnode/lib/VCL/DataStructure.pm [787:937]


sub _automethod : Automethod {
	my $self        = shift;
	my @args        = @_;
	my $method_name = $_;

	# Make sure the function name begins with get_ or set_
	my $mode;
	my $data_identifier;
	if ($method_name =~ /^(get|set)_(.*)/) {
		# $mode stores either 'get' or 'set', data stores the requested data
		$mode            = $1;
		$data_identifier = $2;
	}
	else {
		notify($ERRORS{'WARNING'}, 0, "illegal subroutine name: $method_name");
		return sub { };
	}
	
	# Determines whether or not warnings are shown if data is not initialized
	my $show_warnings = 1;

	# If set, make sure an argument was passed
	my $set_data;
	if ($mode =~ /set/ && defined $args[0]) {
		$set_data = $args[0];
	}
	elsif ($mode =~ /set/) {
		notify($ERRORS{'WARNING'}, 0, "data structure $method_name function was called without an argument");
		return sub { };
	}
	elsif ($mode =~ /get/ && defined $args[0] && !$args[0]) {
		$show_warnings = 0;
	}
	
	my $calling_subroutine = get_calling_subroutine();

	# Check if the sub name is defined in the subroutine mappings hash
	# Return if it isn't
	if (!defined $SUBROUTINE_MAPPINGS{$data_identifier}) {
		if ($calling_subroutine eq 'VCL::DataStructure::can') {
			return;
		}
		else {
			notify($ERRORS{'WARNING'}, 0, "unsupported subroutine name: $method_name");
			return sub { };
		}
	}
	elsif ($calling_subroutine eq 'VCL::DataStructure::can') {
		return sub { };
	}

	# Get the hash path out of the subroutine mappings hash
	my $hash_path = $SUBROUTINE_MAPPINGS{$data_identifier};

	# Replace RESERVATION_ID with the actual reservation ID if it exists in the hash path
	my $reservation_id = $self->reservation_id;
	$reservation_id = 'undefined' if !defined($reservation_id);
	$hash_path =~ s/RESERVATION_ID/$reservation_id/;

	# Replace BLOCKREQUEST_ID with the actual blockrequest ID if it exists in the hash path
	my $blockrequest_id = $self->blockrequest_id;
	$blockrequest_id = 'undefined' if !defined($blockrequest_id);
	$hash_path =~ s/BLOCKREQUEST_ID/$blockrequest_id/;

	# Replace BLOCKTIME_ID with the actual blocktime ID if it exists in the hash path
	my $blocktime_id = $self->blocktime_id;
	$blocktime_id = 'undefined' if !defined($blocktime_id);
	$hash_path =~ s/BLOCKTIME_ID/$blocktime_id/;

	if ($mode =~ /get/) {
		# Get the data from the request_data hash
		# eval is required in order to interpolate the hash path before retrieving the data
		my $key_defined = eval "defined $hash_path";
		
		my $return_value;
		
		# If log or sublog data was requested and not yet populated, attempt to retrieve it
		if (!$key_defined && $data_identifier =~ /^(log_|sublog_)/) {
			notify($ERRORS{'DEBUG'}, 0, "attempting to retrieve log data, requested data has not been initialized ($data_identifier)");
			
			if ($self->get_log_data()) {
				# Log data was retrieved, check if requested data is now populated
				if (eval "defined $hash_path") {
					$return_value = eval $hash_path;
					notify($ERRORS{'DEBUG'}, 0, "log data was retrieved and corresponding data has been initialized for $method_name: $return_value");
				}
				else {
					notify($ERRORS{'WARNING'}, 0, "log data was retrieved but corresponding data has not been initialized for $method_name: $hash_path", $self->request_data) if $show_warnings;
					return sub { };
				}
			}
			else {
				notify($ERRORS{'WARNING'}, 0, "log data could not be retrieved");
				return sub { };
			}
		}
		elsif ($data_identifier =~ /^(management_node)/) {
			# Get the management node info
			# If no argument was specified get_management_node_info will return data for this management node
			my $management_node_info_retrieved = get_management_node_info($args[0]);
			unless ($management_node_info_retrieved) {
				notify($ERRORS{'WARNING'}, 0, "failed to retrieve data for management node");
				return sub { };
			}
			
			# The normal reservation management node data is stored in $ENV->{management_node_info}->{<identifier>}
			# We don't want to overwrite this, but want to temporarily store the data retrieved
			# This allows the $hash_path mechanism to work without alterations
			# Temporarily overwrite this data by using 'local', and set it to the data just retrieved
			# Once the current scope is exited, $ENV->{management_node_info} will return to its original value
			local $ENV->{management_node_info} = $management_node_info_retrieved;
			
			# Attempt to retrieve the value from the temporary data: $ENV->{management_node_info}->{KEY}
			$return_value = eval $hash_path;
		}
		elsif (!$key_defined) {
			if ($show_warnings && $hash_path !~ /(serverrequest|domain)/) {
				notify($ERRORS{'WARNING'}, 0, "corresponding data has not been initialized for $method_name: $hash_path", $self->request_data);
			}
			return sub { };
		}
		else {
			# Just attempt to retrieve the value from the hash path
			$return_value = eval $hash_path;
		}
		
		if (!defined $return_value) {
			if ($show_warnings && $method_name !~ /^(get_management_node_keys)$/) {
				notify($ERRORS{'WARNING'}, 0, "corresponding data is undefined for $method_name: $hash_path");
			}
			return sub { };
		}
		
		# Return the data
		return sub {$return_value;};
	} ## end if ($mode =~ /get/)
	elsif ($mode =~ /set/) {
		eval $hash_path . ' = $set_data';
		
		# Make sure the value was set in the hash
		my $check_value = eval $hash_path;
		if ($check_value eq $set_data) {
			#notify($ERRORS{'DEBUG'}, 0, "data structure updated, hash path: $hash_path, data identifier: $data_identifier");
			return sub {1;};
		}
		else {
			notify($ERRORS{'WARNING'}, 0, "data structure could not be updated, hash path: $hash_path, data identifier: $data_identifier, data:\n" . format_data($set_data));
			return sub {0;};
		}
	} ## end elsif ($mode =~ /set/)  [ if ($mode =~ /get/)
} ## end sub _automethod :