File Coverage

blib/lib/Mobile/WURFL/Resource.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Mobile::WURFL::Resource;
2              
3 1     1   20751 use strict;
  1         2  
  1         35  
4 1     1   4 use warnings;
  1         2  
  1         24  
5 1     1   6 use Carp;
  1         1  
  1         82  
6 1     1   984 use Data::Dumper; # FIXME
  1         9395  
  1         73  
7              
8 1     1   508 use XML::LibXML;
  0            
  0            
9             use BerkeleyDB ;
10             use Storable qw/freeze/;
11             use LWP::Simple;
12             use File::Temp qw/ :POSIX /;
13             use File::Copy qw/ move /;
14              
15             use base 'Mobile::WURFL::Base';
16              
17             our $VERSION = '0.01';
18              
19             sub parsed_data {
20              
21             $_[0]->{'parsed_data'} = $_[1] if @_ > 1;
22             $_[0]->{'parsed_data'};
23             }
24              
25             sub parsed {
26              
27             $_[0]->{'parsed'} = $_[1] if @_ > 1;
28             $_[0]->{'parsed'};
29             }
30              
31             sub version_fields {
32              
33             sort keys %{ $_[0]->parsed_data->{fields}{ version } };
34             }
35              
36             sub version {
37              
38             $_[0]->parsed_data->{ version };
39             }
40              
41             sub attribute_fields {
42              
43             sort keys %{ $_[0]->parsed_data->{fields}{ attributes } };
44             }
45              
46             sub capability_fields {
47              
48             sort keys %{ $_[0]->parsed_data->{fields}{ capabilities } };
49             }
50              
51             sub update {
52              
53             my ($self, $uri, $xml) = @_;
54              
55             $uri ||= $self->wurfl_uri;
56             $xml ||= $self->wurfl_xml;
57             my $tmp_name = tmpnam().".$$";
58              
59             my $rc = LWP::Simple::getstore( $uri, $tmp_name);
60              
61             if ($rc == 200) {
62             $self->error(0);
63             move($tmp_name, $xml) or die "can't move $tmp_name to $xml: $!";
64             } else {
65             $self->error(1);
66             $self->error_message("$rc");
67             }
68              
69             return $rc == 200 ? 1 : 0;
70             }
71              
72             sub parse {
73              
74             my ($self, $xml) = @_;
75              
76             $self->parsed(0);
77            
78             my $o = {};
79            
80             eval {
81             my $parser = XML::LibXML->new();
82             my $doc = $parser->parse_file( $xml || $self->wurfl_xml );
83            
84             my ($wurfl) = $doc->getElementsByTagName('wurfl');
85            
86             my ($version) = $wurfl->getElementsByTagName('version');
87             foreach my $field (qw/ver last_updated official_url/) {
88             $o->{version}{$field} = $version->getElementsByTagName($field)->[0]->textContent;
89             $o->{fields}{version}{ $field }++;
90             }
91            
92             my ($devices) = $wurfl->getElementsByTagName('devices');
93             foreach my $device ( $devices->childNodes ) {
94             next unless $device->nodeName eq 'device';
95             my $device_id = $device->getAttribute( 'id' );
96             my $user_agent = $device->getAttribute( 'user_agent' );
97             $o->{user_agents}{$user_agent} = $device_id;
98            
99             foreach my $attribute ( $device->attributes ) {
100             my $name = $attribute->nodeName;
101             $o->{devices}{$device_id}{attributes}{ $name } = $attribute->getValue;
102             $o->{fields}{attributes}{ $name }++;
103             }
104            
105             foreach my $group ( $device->childNodes ) {
106             next unless $group->nodeName eq 'group';
107             #my $group_id = $group->getAttribute( 'id' );
108            
109             foreach my $capability ( $group->childNodes ) {
110             next unless $capability->nodeName eq 'capability';
111             my $name = $capability->getAttribute( 'name' );
112             $o->{devices}{$device_id}{capabilities}{ $name } = $capability->getAttribute( 'value' );
113             $o->{fields}{capabilities}{ $name }++;
114             }
115             }
116             }
117              
118             };
119            
120             if ($@) {
121             $self->error(1);
122             $self->error_message("$@");
123             $self->parsed(0);
124             } else {
125             $self->error(0);
126             $self->parsed_data( $o );
127             $self->parsed(1);
128             }
129            
130             return $self->error;
131             }
132              
133              
134             sub create_bdb {
135              
136             my ($self, $bdb) = @_;
137              
138             unless ($self->parsed) {
139             $self->error(1);
140             $self->error_message('no data parsed');
141             return 0;
142             }
143              
144             my $tmp_name = tmpnam().".$$";
145              
146             my $db_version = BerkeleyDB::Btree->new(
147             -Filename => $tmp_name,
148             -Subname => 'version',
149             -Flags => DB_CREATE
150             ) or die "Cannot open file $tmp_name: $!: $BerkeleyDB::Error" ;
151              
152             while (my ($field, $value) = each %{ $self->version }) {
153             print "$field: $value\n";
154             $db_version->db_put( $field, $value );
155             }
156              
157             $db_version->db_close;
158              
159             my $db_capabilities = BerkeleyDB::Btree->new(
160             -Filename => $tmp_name,
161             -Subname => 'capabilities',
162             -Flags => DB_CREATE
163             ) or die "Cannot open file $tmp_name: $!: $BerkeleyDB::Error" ;
164              
165             foreach my $capability ($self->capability_fields) {
166             $db_capabilities->db_put( $capability, 1 );
167             }
168            
169             $db_capabilities->db_close;
170              
171             my $db_attributes = BerkeleyDB::Btree->new(
172             -Filename => $tmp_name,
173             -Subname => 'attributes',
174             -Flags => DB_CREATE
175             ) or die "Cannot open file $tmp_name: $!: $BerkeleyDB::Error" ;
176              
177             foreach my $attribute ($self->attribute_fields) {
178             $db_attributes->db_put( $attribute, 1 );
179             }
180              
181             $db_attributes->db_close;
182            
183             my $tmp_name_map = tmpnam().".$$";
184              
185             my $db_map = BerkeleyDB::Btree->new(
186             -Filename => $tmp_name_map,
187             -Flags => DB_CREATE
188             ) or die "Cannot open file $tmp_name_map: $!: $BerkeleyDB::Error" ;
189              
190             my $tmp_name_data = tmpnam().".$$";
191              
192             my $db_devices = BerkeleyDB::Btree->new(
193             -Filename => $tmp_name_data,
194             -Flags => DB_CREATE
195             ) or die "Cannot open file $tmp_name_data: $!: $BerkeleyDB::Error" ;
196              
197             my $count = 0;
198             my $error;
199             my $o = $self->parsed_data;
200              
201             while (my ($user_agent, $device_id) = each %{ $o->{user_agents} }) {
202              
203             my %final;
204             my $current_id = $device_id;
205             $final{attributes} = $o->{devices}{$device_id}{attributes};
206              
207             my $stop = 0;
208             while (not $stop) {
209              
210             my $current = $o->{devices}{$current_id};
211              
212             while (my ($name, $value) = each %{ $current->{capabilities} }) {
213             $final{capabilities}{$name} = $value
214             unless (defined $final{capabilities}{$name});
215             }
216              
217             $stop++ if $current->{attributes}{id} eq 'generic';
218             $current_id = $current->{attributes}{fall_back};
219             }
220              
221             $error = $db_map->db_put("-$user_agent", $device_id);
222             confess "map_ua/db_put: $!: $BerkeleyDB::Error\n" if $error;
223              
224             $error = $db_devices->db_put($device_id, freeze \%final);
225             confess "devices/db_put: $!: $BerkeleyDB::Error\n" if $error;
226              
227             if ($count % 250 == 0) {
228             $error = $db_devices->db_sync;
229             confess "devices/db_sync: $!: $BerkeleyDB::Error\n" if $error;
230              
231             $error = $db_map->db_sync;
232             confess "map_ua/db_sync: $!: $BerkeleyDB::Error\n" if $error;
233             }
234              
235             $count++;
236             }
237              
238             $db_devices->db_sync;
239             $db_devices->db_close;
240              
241             $db_map->db_sync;
242             $db_map->db_close;
243              
244             $bdb ||= $self->wurfl_bdb;
245              
246             move($tmp_name, "$bdb/wurfl.db") or die "$bdb/wurfl.db: $!";
247             move($tmp_name_map, "$bdb/wurfl_map.db") or die "$bdb/wurfl_map.db: $!";
248             move($tmp_name_data, "$bdb/wurfl_data.db") or die "$bdb/wurfl_data.db: $!";
249              
250             return 1;
251             }
252              
253              
254             1;
255             __END__