File Coverage

blib/lib/Tie/JCR.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Tie::JCR;
2              
3 2     2   1604 use strict;
  2         4  
  2         116  
4 2     2   10 use warnings;
  2         5  
  2         98  
5              
6             our $VERSION = '0.02';
7              
8 2     2   20 use Carp;
  2         3  
  2         172  
9 2     2   2086 use Java::JCR;
  0            
  0            
10              
11             =head1 NAME
12              
13             Tie::JCR - A tied hash interface for Java::JCR::Node
14              
15             =head1 SYNOPSIS
16              
17             use Data::Dumper;
18             use Java::JCR;
19             use Java::JCR::Jackrabbit;
20             use Tie::JCR;
21              
22             my $repository = Java::JCR::Jackrabbit->new;
23             my $session = $respoitory->session;
24             my $root_node = $session->get_root_node;
25             tie my %root, 'Tie::JCR', $root_node;
26              
27             # Expensive, but we can dump the whole tree:
28             print Dumper(\%root);
29              
30             my $type = $root{'jcr:primaryType'};
31             my $uuid = $root{'jcr:uuid'};
32             my $foo = $root{'foo'};
33             my $nested_bar = $root{'qux'}{'baz'}{'bar'};
34              
35             =head1 DESCRIPTION
36              
37             This provides a very simple, read-only interface to a node from L. Each key represents the names of items within the node. Each value is either a scalar for non-multiple child properties, an array for multiple child properties, or nested hashes for child nodes. In the case of same-name children, you may see an array returned containing scalars and hashes for a mixture of properties and nodes.
38              
39             =head2 CHANGES ARE TRANSIENT
40              
41             Changes made to the tied hash are transient and only act to override the local cache. If you want to make changes to node, you must do so through the L API. This is primarily meant as a convenience interface, not as a serious front-end to the JCR.
42              
43             =head2 SUPPORTED OPERATIONS
44              
45             The only hash operation that isn't implemented is CLEAR. Therefore, all of the following will work:
46              
47             tie my %hash, 'Tie::JCR', $node;
48             my $value = $node{'property_name'};
49             my $child_node = $node{'node_name'};
50              
51             # store a value temporarily IN THIS HASH ONLY, doesn't affect the JCR
52             $node{'temp_value'} = 'blah';
53              
54             # make the property undefined IN THIS HASH ONLY, doesn't affect the JCR
55             delete $node{'property_name'};
56              
57             # defined === exists since null values are not permitted in the JCR
58             my $has_item = exists $node{'item_name'};
59              
60             my @keys = keys %node;
61             my @values = values %node;
62             while (my ($key, $value) = each %node) {
63             print $key, " = ", $value, "\n";
64             }
65              
66             # returns true if has_nodes or has_properties
67             my $has_children = scalar %node;
68              
69             =head2 CACHING
70              
71             The fetch, store, and delete operations modify an internal cache. By using the cache, some speed can be gained by avoiding a second JCR API call. This is also how the store and delete operations make transient changes, by storing values in the cache.
72              
73             =head2 INTERNAL METHODS
74              
75             In addition, you can use the tied object to get the node back:
76              
77             my $node_obj = (tied %node)->node;
78              
79             You may also wish to clear out any local changes used with store or otherwise held in the internal cache:
80              
81             (tied %node)->clear_cache;
82              
83             =head2 JCR TYPES
84              
85             The fetch operation handles all the various JCR types properly. Longs will be treated as longs, doubles as doubles, booleans as booleans, dates as dates, references as nodes, and everything else as a string.
86              
87             =cut
88              
89             sub TIEHASH {
90             my ($class, $node) = @_;
91             return bless {
92             node => $node,
93             cache => {},
94             }, $class;
95             }
96              
97             sub node {
98             my $self = shift;
99             return $self->{node};
100             }
101              
102             sub cache {
103             my $self = shift;
104             return $self->{cache};
105             }
106              
107             sub clear_cache {
108             my $self = shift;
109             $self->{cache} = {};
110             }
111              
112             sub FETCH {
113             my ($self, $key) = @_;
114              
115             if (exists $self->cache->{$key}) {
116             return $self->cache->{$key};
117             }
118              
119             else {
120             my $node = $self->node;
121             if ($node->has_node($key)) {
122             tie my %child_node, 'Tie::JCR', $node->get_node($key);
123             return $self->cache->{$key} = \%child_node;
124             }
125              
126             elsif ($node->has_property($key)) {
127             my $property = $node->get_property($key);
128             my $definition = $property->get_definition;
129             my $type = $definition->get_required_type;
130             my $multiple = $definition->is_multiple;
131              
132             my $get_function
133             = $type == $Java::JCR::PropertyType::DATE ? 'get_date'
134             : $type == $Java::JCR::PropertyType::BOOLEAN ? 'get_boolean'
135             : $type == $Java::JCR::PropertyType::DOUBLE ? 'get_double'
136             : $type == $Java::JCR::PropertyType::LONG ? 'get_long'
137             : 'get_string';
138              
139             my $value
140             = $multiple ?
141             [ map { $_->$get_function() } @{ $property->get_values } ]
142             : $property->$get_function();
143              
144             if ($type == $Java::JCR::PropertyType::REFERENCE) {
145             my $session = $node->get_session;
146              
147             if ($multiple) {
148             $value = {
149             map {
150             my $node = $session->get_node_by_uuid($_);
151             tie my %node, 'Tie::JCR', $node;
152             ($node->get_name => \%node);
153             } @$value
154             };
155             }
156              
157             else {
158             $value = $session->get_node_by_uuid($value);
159             }
160             }
161              
162             return $self->cache->{$key} = $value;
163             }
164              
165             else {
166             return $self->cache->{$key} = undef;
167             }
168             }
169             }
170              
171             sub STORE {
172             my ($self, $key, $value) = @_;
173              
174             return $self->cache->{$key} = $value;
175             }
176              
177             sub DELETE {
178             my ($self, $key, $value) = @_;
179              
180             $self->cache->{$key} = undef;
181             }
182              
183             sub CLEAR {
184             my ($self) = @_;
185              
186             die "CLEAR is not implemented.";
187             }
188              
189             sub EXISTS {
190             my ($self, $key) = @_;
191             my $node = $self->node;
192              
193             if (exists $self->cache->{$key}) {
194             return defined $self->cache->{$key};
195             }
196              
197             else {
198             return $node->has_node($key) || $node->has_property($key);
199             }
200             }
201              
202             sub FIRSTKEY {
203             my ($self) = @_;
204             my $node = $self->node;
205              
206             $self->{current_iterators} = [ $node->get_nodes, $node->get_properties ];
207              
208             return $self->NEXTKEY;
209             }
210              
211             sub NEXTKEY {
212             my ($self) = @_;
213              
214             my $current_iterators = $self->{current_iterators};
215             if (defined $current_iterators && @$current_iterators) {
216             while (@$current_iterators && !$current_iterators->[0]->has_next) {
217             shift @$current_iterators;
218             }
219              
220             if (!@$current_iterators) {
221             return;
222             }
223              
224             my $curr_iter = $current_iterators->[0];
225            
226             my $item
227             = $curr_iter->can('next_node') ? $curr_iter->next_node
228             : $curr_iter->can('next_property') ? $curr_iter->next_property
229             : $curr_iter->can('next') ? $curr_iter->next
230             : croak "Unknown iterator type missing next_node, ",
231             "next_property, and next method. An iterator must ",
232             "provide one of those.";
233              
234             return $item->get_name;
235             }
236              
237             else {
238             return;
239             }
240             }
241              
242             sub SCALAR {
243             my ($self) = @_;
244             my $node = $self->node;
245              
246             return $node->has_nodes || $node->has_properties;
247             }
248              
249             =head1 AUTHOR
250              
251             Andrew Sterling Hanenkamp, Ehanenkamp@cpan.orgE
252              
253             =head1 LICENSE AND COPYRIGHT
254              
255             Copyright 2006 Andrew Sterling Hanenkamp Ehanenkamp@cpan.orgE. All
256             Rights Reserved.
257              
258             This module is free software; you can redistribute it and/or modify it under
259             the same terms as Perl itself. See L.
260              
261             This program is distributed in the hope that it will be useful, but WITHOUT
262             ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
263             FOR A PARTICULAR PURPOSE.
264              
265             =cut
266              
267             1