Connector

 view release on metacpan or  search on metacpan

lib/Connector/Builtin/Memory.pm  view on Meta::CPAN

# Connector::Builtin::Memory
#
# Proxy class for reading YAML configuration
#
# Written by Scott Hardin, Martin Bartosch and Oliver Welter
# for the OpenXPKI project 2012
#
# THIS IS NOT WORKING IN A FORKING ENVIRONMENT!


package Connector::Builtin::Memory;

use strict;
use warnings;
use English;
use Data::Dumper;

use Moose;
extends 'Connector::Builtin';

has '+LOCATION' => ( required => 0 );

has 'primary_attribute' => (
    is => 'ro',
    isa => 'Str',
    predicate => 'has_primary_attribute',
);

sub _build_config {
    my $self = shift;
    $self->_config( {} );
}

sub _get_node {

    my $self = shift;
    my @path = $self->_build_path_with_prefix( shift );

    $self->log()->trace('get node for path'. Dumper \@path);

    my $ptr = $self->_config();

    while ( scalar @path ) {
        my $entry = shift @path;
        if ( ref $ptr eq 'HASH' && exists $ptr->{$entry} ) {
            my $type = ref $ptr->{$entry};
            if ( $type eq 'HASH' || $type eq 'ARRAY' || scalar @path == 0) {
                $ptr = $ptr->{$entry};
            }
            else {
                $self->log()->debug("tried to walk over unexpected node type: $type");
                return $self->_node_not_exists( $entry );
            }
        }
        elsif ( ref $ptr eq 'ARRAY' && $entry =~ m{\A\d+\z} && exists $ptr->[$entry] ) {
            my $type = ref $ptr->[$entry];
            if ( $type eq 'HASH' || $type eq 'ARRAY' || scalar @path == 0) {
                $ptr = $ptr->[$entry];
            }
            else {
                $self->log()->debug("tried to walk over unexpected node type: $type");
                return $self->_node_not_exists( $entry );
            }
        } else {
            return $self->_node_not_exists($entry);
        }
    }

    return $ptr;

}

sub get {

    my $self = shift;
    my $value = $self->_get_node( shift );

    return $self->_node_not_exists() unless (defined $value);

    if (ref $value ne '') {
        die "requested value is not a scalar"
            unless ($self->has_primary_attribute() && ref $value eq 'HASH');

        return $self->_node_not_exists()
            unless (defined $value->{$self->primary_attribute});

        die "primary_attribute is not a scalar"
            unless (ref $value->{$self->primary_attribute} eq '');

        return $value->{$self->primary_attribute};
    }

    return $value;

}

sub get_size {

    my $self = shift;
    my $node = $self->_get_node( shift );

    return 0 unless(defined $node);

    if ( ref $node ne 'ARRAY' ) {
        die "requested value is not a list"
    }

    return scalar @{$node};
}

sub get_list {

    my $self = shift;
    my $path = shift;

    my $node = $self->_get_node( $path );

    return $self->_node_not_exists( $path ) unless(defined $node);

    if ( ref $node ne 'ARRAY' ) {
        die "requested value is not a list"
    }

    return @{$node};
}

sub get_keys {

    my $self = shift;
    my $path = shift;

    my $node = $self->_get_node( $path );

    return @{[]} unless(defined $node);

    if ( ref $node ne 'HASH' ) {
        die "requested value is not a hash"
    }

    return keys %{$node};
}

sub get_hash {

    my $self = shift;
    my $path = shift;

    my $node = $self->_get_node( $path );

    return $self->_node_not_exists( $path ) unless(defined $node);

    if ( ref $node ne 'HASH' ) {
        die "requested value is not a hash"
    }

    return { %$node };
}

sub get_meta {

    my $self = shift;

    my $node = $self->_get_node( shift );

    $self->log()->trace('get_node returned '. Dumper $node);

    if (!defined $node) {
        # die_on_undef already handled by get_node
        return;
    }

    my $meta = {};

    if (ref $node eq '') {
        $meta = {TYPE  => "scalar", VALUE => $node };
    } elsif (ref $node eq "SCALAR") {
        $meta = {TYPE  => "reference", VALUE => $$node };
    } elsif (ref $node eq "ARRAY") {
        $meta = {TYPE  => "list", VALUE => $node };
    } elsif (ref $node eq "HASH") {
        my @keys = keys(%{$node});
        $meta = {TYPE  => "hash", VALUE => \@keys };
    } elsif (blessed($node) && $node->isa('Connector')) {
        $meta = {TYPE  => "connector", VALUE => $node };
    } else {
        die "Unsupported node type: " . ref $node;
    }
    return $meta;
}

sub exists {

    my $self = shift;

    my $value = 0;
    eval {
        $value = defined $self->_get_node( shift );
    };
    return $value;

}

sub set {

    my $self = shift;
    my @path = $self->_build_path_with_prefix( shift );

    my $value = shift;

    my $ptr = $self->_config();

    while (scalar @path > 1) {
        my $entry = shift @path;
        if (!exists $ptr->{$entry}) {
            $ptr->{$entry} = {};
        } elsif (ref $ptr->{$entry} ne "HASH") {
            confess('Try to step over a value node at ' . $entry);
        }
        $ptr = $ptr->{$entry};
    }

    my $entry = shift @path;

    if (!defined $value) {
        delete $ptr->{$entry};
        return;
    }

    if (exists $ptr->{$entry}) {
        if (ref $ptr->{$entry} ne ref $value) {
            confess('Try to override data type at node ' . $entry);
        }
    }
    $ptr->{$entry} = $value;
    return 1;
}


no Moose;
__PACKAGE__->meta->make_immutable;

1;
__END__

=head1 Name

Connector::Builtin::Memory

=head1 Description

A connector implementation to allow memory based caching

=head1 Parameters

=over

=item LOCATION

Not used

=item primary_attribute

If your data consists of hashes as leaf nodes, set this to the name of
the node that is considered the primary attribute, e.g. the name of a
person. If you now access the key on the penultimate level using I<get>
you will receive the value of this attribute back.

    user1234:
        name: John Doe
        email: john.doe@acme.com

When you call I<get(user1234)> on this structure, the connector will
usually die with a "not a scalar" error. With I<primary_attribute = name>
you will get back I<John Doe>.

=back



( run in 0.755 second using v1.01-cache-2.11-cpan-a838e43af63 )