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   3000502 use strict;
  2         14  
  2         80  
13 2     2   22 use warnings;
  2         4  
  2         70  
14 2     2   17 use English;
  2         4  
  2         18  
15 2     2   1008 use Config::Versioned;
  2         8  
  2         73  
16 2     2   11 use Data::Dumper;
  2         5  
  2         119  
17              
18 2     2   11 use Moose;
  2         12  
  2         17  
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   13 my $self = shift;
34              
35 3         103 my $config = Config::Versioned->new( { dbpath => $self->LOCATION(), } );
36              
37 3 50       3773 if ( not defined $config ) {
38 0         0 return; # try to throw exception
39             }
40 3         18 $self->version( $config->version() );
41 3         178 return $config;
42             }
43              
44              
45             sub fetch_head_commit {
46 3     3 1 11 my $self = shift;
47 3         180 return $self->_config()->version();
48             }
49              
50             sub get {
51 24     24 1 1521 my $self = shift;
52 24         112 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         987 my $val = $self->_config()->get( $path, $self->version() );
56              
57 24 100       220192 $self->_node_not_exists( $path ) unless (defined $val);
58              
59 24         350 return $val;
60             }
61              
62             sub get_size {
63              
64 1     1 1 15 my $self = shift;
65 1         5 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         39 my $val = $self->_config()->get( $path, $self->version() );
71              
72 1 50       7947 return 0 unless( $val );
73              
74 1 50       16 die "requested path looks not like a list" unless( $val =~ /^\d+$/);
75              
76 1         13 return $val;
77              
78             };
79              
80             sub get_list {
81              
82 1     1 1 5 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         38 my @keys = $self->_config()->get( $path, $self->version() );
87 1         8110 my @list;
88              
89 1 50       11 if (!@keys) {
90 0         0 $self->_node_not_exists( $path ) ;
91 0         0 return @list;
92             };
93              
94 1         4 foreach my $key (@keys) {
95 4 50       26559 if ($key !~ /^\d+$/) {
96 0         0 die "requested path looks not like a list";
97             }
98 4         144 push @list, $self->_config()->get( $path.$self->DELIMITER().$key, $self->version() );
99             }
100 1         8745 return @list;
101             };
102              
103             sub get_keys {
104              
105 2     2 1 15 my $self = shift;
106 2         13 my $path = $self->_build_delimited_cv_path( shift );
107              
108 2         103 my @keys = $self->_config()->get( $path, $self->version() );
109              
110 2 50       15105 return @{[]} unless(@keys);
  0         0  
111              
112 2         41 return @keys;
113              
114             };
115              
116             sub get_hash {
117              
118 4     4 1 866 my $self = shift;
119 4         18 my $path = $self->_build_delimited_cv_path( shift );
120              
121 4         150 my @keys = $self->_config()->get( $path, $self->version() );
122              
123 4 50       32211 return $self->_node_not_exists( $path ) unless(@keys);
124 4         12 my $data = {};
125 4         49 foreach my $key (@keys) {
126 9         43815 $data->{$key} = $self->_config()->get( $path.$self->DELIMITER().$key, $self->version() );
127             }
128 4         35533 return $data;
129             };
130              
131              
132             sub get_reference {
133 1     1 1 4 my $self = shift;
134 1         4 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         41 my $val = $self->_config()->get( $path, $self->version() );
138              
139 1 50       8380 $self->_node_not_exists( $path ) unless (defined $val);
140              
141 1 50       6 if (ref $val ne "SCALAR") {
142 0         0 die "requested path looks not like a reference";
143             }
144              
145 1         7 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 275 my $self = shift;
153 173         392 my $path = $self->_build_delimited_cv_path( shift );
154              
155 173         6293 my @keys = $self->_config()->get( $path, $self->version() );
156              
157 173 100       1578711 return $self->_node_not_exists( $path ) unless( @keys );
158              
159 94         353 my $meta = {
160             TYPE => "hash"
161             };
162              
163             # Do some guessing
164 94 100       387 if (@keys == 1) {
    100          
165             # a redirector reference
166 69 100       247 if (ref $keys[0] eq "SCALAR") {
    50          
167 29         108 $meta->{TYPE} = "reference";
168 29         63 $meta->{VALUE} = ${$keys[0]};
  29         95  
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         1252 my $val = $self->_config()->get( $path . $self->DELIMITER() . $keys[0], $self->version() );
177 40 100       393429 if (!defined $val) {
    100          
178 27         115 $meta->{TYPE} = "scalar";
179 27         88 $meta->{VALUE} = $keys[0];
180             } elsif( $keys[0] =~ /^\d+$/) {
181 2         8 $meta->{TYPE} = "list";
182             }
183             }
184             } elsif( $keys[0] =~ /^\d+$/) {
185 2         5 $meta->{TYPE} = "list";
186             }
187              
188 94         453 return $meta;
189             }
190              
191              
192             sub exists {
193              
194 5     5 1 14 my $self = shift;
195 5         15 my $path = $self->_build_delimited_cv_path( shift );
196 5         45 my $node;
197 5         15 eval {
198 5         152 $node = $self->_config()->get( $path, $self->version() );
199             };
200 5         35303 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   345 my $self = shift;
208 211         602 my @path = $self->_build_path_with_prefix( shift );
209 211         7337 return join ( $self->_config()->delimiter(), @path );
210              
211             }
212              
213              
214 2     2   16822 no Moose;
  2         7  
  2         24  
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