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 |