File Coverage

blib/lib/Connector/Proxy/Config/Versioned.pm
Criterion Covered Total %
statement 93 101 92.0
branch 24 34 70.5
condition n/a
subroutine 18 18 100.0
pod 9 9 100.0
total 144 162 88.8


line stmt bran cond sub pod time code
1             # Connector::Proxy::Config::Versioned
2             #
3             # Proxy class for reading Config::Versioned configuration
4             #
5             # Written by Scott Hardin, Martin Bartosch and Oliver Welter
6             # for the OpenXPKI project 2012
7              
8             # Todo - need some more checks on value types
9              
10             package Connector::Proxy::Config::Versioned;
11              
12 2     2   2420316 use strict;
  2         11  
  2         59  
13 2     2   11 use warnings;
  2         4  
  2         51  
14 2     2   9 use English;
  2         4  
  2         16  
15 2     2   732 use Config::Versioned;
  2         6  
  2         73  
16 2     2   12 use Data::Dumper;
  2         4  
  2         91  
17              
18 2     2   10 use Moose;
  2         4  
  2         32  
19             extends 'Connector::Proxy';
20              
21             has '+_config' => (
22             lazy => 1,
23             );
24              
25             has 'version' => (
26             is => 'rw',
27             isa => 'Str',
28             required => 0,
29             builder => 'fetch_head_commit',
30             );
31              
32             sub _build_config {
33 3     3   16 my $self = shift;
34              
35 3         77 my $config = Config::Versioned->new( { dbpath => $self->LOCATION(), } );
36              
37 3 50       3074 if ( not defined $config ) {
38 0         0 return; # try to throw exception
39             }
40 3         21 $self->version( $config->version() );
41 3         150 return $config;
42             }
43              
44              
45             sub fetch_head_commit {
46 3     3 1 8 my $self = shift;
47 3         156 return $self->_config()->version();
48             }
49              
50             sub get {
51 24     24 1 1180 my $self = shift;
52 24         90 my $path = $self->_build_delimited_cv_path( shift );
53              
54             # We need a change to C:V backend to check if this is a node or not
55 24         818 my $val = $self->_config()->get( $path, $self->version() );
56              
57 24 100       184038 $self->_node_not_exists( $path ) unless (defined $val);
58              
59 24         235 return $val;
60             }
61              
62             sub get_size {
63              
64 1     1 1 13 my $self = shift;
65 1         3 my $path = $self->_build_delimited_cv_path( shift );
66              
67             # We check if the value is an integer to see if this looks like
68             # an array - This is not bullet proof but should do
69              
70 1         32 my $val = $self->_config()->get( $path, $self->version() );
71              
72 1 50       6603 return 0 unless( $val );
73              
74 1 50       18 die "requested path looks not like a list" unless( $val =~ /^\d+$/);
75              
76 1         8 return $val;
77              
78             };
79              
80             sub get_list {
81              
82 1     1 1 3 my $self = shift;
83 1         4 my $path = $self->_build_delimited_cv_path( shift );
84              
85             # C::V uses an array with numeric keys internally - we use this to check if this is an array
86 1         42 my @keys = $self->_config()->get( $path, $self->version() );
87 1         6789 my @list;
88              
89 1 50       4 if (!@keys) {
90 0         0 $self->_node_not_exists( $path ) ;
91 0         0 return @list;
92             };
93              
94 1         3 foreach my $key (@keys) {
95 4 50       21969 if ($key !~ /^\d+$/) {
96 0         0 die "requested path looks not like a list";
97             }
98 4         109 push @list, $self->_config()->get( $path.$self->DELIMITER().$key, $self->version() );
99             }
100 1         7235 return @list;
101             };
102              
103             sub get_keys {
104              
105 2     2 1 6 my $self = shift;
106 2         18 my $path = $self->_build_delimited_cv_path( shift );
107              
108 2         74 my @keys = $self->_config()->get( $path, $self->version() );
109              
110 2 50       12535 return @{[]} unless(@keys);
  0         0  
111              
112 2         22 return @keys;
113              
114             };
115              
116             sub get_hash {
117              
118 4     4 1 697 my $self = shift;
119 4         16 my $path = $self->_build_delimited_cv_path( shift );
120              
121 4         126 my @keys = $self->_config()->get( $path, $self->version() );
122              
123 4 50       26618 return $self->_node_not_exists( $path ) unless(@keys);
124 4         9 my $data = {};
125 4         26 foreach my $key (@keys) {
126 9         36409 $data->{$key} = $self->_config()->get( $path.$self->DELIMITER().$key, $self->version() );
127             }
128 4         29040 return $data;
129             };
130              
131              
132             sub get_reference {
133 1     1 1 3 my $self = shift;
134 1         2 my $path = $self->_build_delimited_cv_path( shift );
135              
136             # We need a change to C:V backend to check if this is a node or not
137 1         35 my $val = $self->_config()->get( $path, $self->version() );
138              
139 1 50       6769 $self->_node_not_exists( $path ) unless (defined $val);
140              
141 1 50       5 if (ref $val ne "SCALAR") {
142 0         0 die "requested path looks not like a reference";
143             }
144              
145 1         5 return $$val;
146             };
147              
148              
149             # This can be a very expensive method and includes some guessing
150             sub get_meta {
151              
152 173     173 1 247 my $self = shift;
153 173         381 my $path = $self->_build_delimited_cv_path( shift );
154              
155 173         5090 my @keys = $self->_config()->get( $path, $self->version() );
156              
157 173 100       1322146 return $self->_node_not_exists( $path ) unless( @keys );
158              
159 94         288 my $meta = {
160             TYPE => "hash"
161             };
162              
163             # Do some guessing
164 94 100       309 if (@keys == 1) {
    100          
165             # a redirector reference
166 69 100       263 if (ref $keys[0] eq "SCALAR") {
    50          
167 29         78 $meta->{TYPE} = "reference";
168 29         57 $meta->{VALUE} = ${$keys[0]};
  29         85  
169              
170             # Node with empty value
171             } elsif ($keys[0] eq "") {
172 0         0 $meta->{TYPE} = "scalar";
173 0         0 $meta->{VALUE} = "";
174             } else {
175             # probe if there is something "below"
176 40         1092 my $val = $self->_config()->get( $path . $self->DELIMITER() . $keys[0], $self->version() );
177 40 100       330057 if (!defined $val) {
    100          
178 27         78 $meta->{TYPE} = "scalar";
179 27         73 $meta->{VALUE} = $keys[0];
180             } elsif( $keys[0] =~ /^\d+$/) {
181 2         7 $meta->{TYPE} = "list";
182             }
183             }
184             } elsif( $keys[0] =~ /^\d+$/) {
185 2         5 $meta->{TYPE} = "list";
186             }
187              
188 94         369 return $meta;
189             }
190              
191              
192             sub exists {
193              
194 5     5 1 12 my $self = shift;
195 5         12 my $path = $self->_build_delimited_cv_path( shift );
196 5         36 my $node;
197 5         12 eval {
198 5         135 $node = $self->_config()->get( $path, $self->version() );
199             };
200 5         29119 return defined $node;
201              
202             }
203              
204             # return the path as string as used in C::V using the delimiter of C::V!
205             sub _build_delimited_cv_path {
206              
207 211     211   269 my $self = shift;
208 211         569 my @path = $self->_build_path_with_prefix( shift );
209 211         6059 return join ( $self->_config()->delimiter(), @path );
210              
211             }
212              
213              
214 2     2   14456 no Moose;
  2         5  
  2         17  
215             __PACKAGE__->meta->make_immutable;
216              
217             1;
218             __END__
219              
220             =head1 Name
221              
222             Connector::Proxy::Config::Versioned
223              
224             =head1 Description
225              
226             Fetch values ftom the underlying Config::Versioned repository.
227             On init, the commit id of the head is written into the local
228             version property and all further queries are done against this
229             commit id. You can set the version to be used at any time by passing
230             the commit id (sha1 hash) to C<version>.
231              
232             To advance to the head commit of the underlying repository, use
233             C<fetch_head_commit> to get the id of the head and set it using
234             C<version>
235              
236             =head1 methods
237              
238             =head2 fetch_head_commit
239              
240             Receive the sha1 commit id of the topmost commit of the underlying repository.
241              
242             =head2 version
243             get/set the value of the version used for all get* requests.
244