File Coverage

blib/lib/Apache/Tika/Server.pm
Criterion Covered Total %
statement 27 127 21.2
branch 0 44 0.0
condition 0 24 0.0
subroutine 9 20 45.0
pod 0 10 0.0
total 36 225 16.0


line stmt bran cond sub pod time code
1             package Apache::Tika::Server;
2 1     1   65337 use strict;
  1         3  
  1         33  
3 1     1   5 use Carp qw(croak);
  1         2  
  1         48  
4             # Fire up/stop a Tika instance
5 1     1   562 use Moo 2;
  1         10939  
  1         6  
6 1     1   1798 use Apache::Tika::DocInfo;
  1         4  
  1         32  
7 1     1   613 use Data::Dumper;
  1         6668  
  1         62  
8 1     1   526 use Promises;
  1         15144  
  1         12  
9              
10 1     1   680 use Filter::signatures;
  1         24013  
  1         13  
11 1     1   33 use feature 'signatures';
  1         2  
  1         31  
12 1     1   38 no warnings 'experimental::signatures';
  1         4  
  1         1684  
13              
14             =head1 SYNOPSIS
15              
16             use Apache::Tika::Server;
17              
18             # Launch our own Apache Tika instance
19             my $tika= Apache::Tika::Server->new(
20             jarfile => $tika_path,
21             );
22             $tika->launch;
23              
24             my $fn= shift;
25              
26             use Data::Dumper;
27             my $info = $tika->get_all( $fn );
28             print Dumper $info->meta($fn);
29             print $info->content($fn);
30             # ...
31             print $info->meta->{"meta:language"};
32             # en
33              
34             =cut
35              
36             our $VERSION = '0.08';
37              
38             extends 'Apache::Tika::Async';
39              
40             sub load_module {
41 0     0 0   my( $module ) = @_;
42 0           $module =~ s!::!/!g;
43 0           require "$module.pm"
44             }
45              
46             has pid => (
47             is => 'rw',
48             #isa => 'Int',
49             );
50              
51             has port => (
52             is => 'ro',
53             #isa => 'Int',
54             default => sub { 9998 },
55             );
56              
57             has connection_class => (
58             is => 'ro',
59             default => 'Apache::Tika::Connection::AEHTTP',
60             );
61              
62             has ua => (
63             is => 'ro',
64             #isa => 'Str',
65             default => sub { load_module( $_[0]->connection_class ); $_[0]->connection_class->new },
66             );
67              
68             sub cmdline {
69 0     0 0   my( $self )= @_;
70             $self->java,
71 0           @{$self->java_args},
72             '-jar',
73             $self->jarfile,
74             #'--port', $self->port,
75 0           @{$self->tika_args},
  0            
76             };
77              
78 0     0 0   sub spawn_child_win32( $self, @cmd ) {
  0            
  0            
  0            
79 0           system(1, @cmd)
80             }
81              
82 0     0 0   sub spawn_child_posix( $self, @cmd ) {
  0            
  0            
  0            
83 0           require POSIX;
84 0           POSIX->import("setsid");
85              
86             # daemonize
87 0 0         defined(my $pid = fork()) || die "can't fork: $!";
88 0 0         if( $pid ) { # non-zero now means I am the parent
89 0           return $pid;
90             };
91              
92             # We are the child, close about everything, then exec
93 0 0         chdir("/") || die "can't chdir to /: $!";
94 0 0         (setsid() != -1) || die "Can't start a new session: $!";
95 0 0         open(STDERR, ">&STDOUT") || die "can't dup stdout: $!";
96 0 0         open(STDIN, "< /dev/null") || die "can't read /dev/null: $!";
97 0 0         open(STDOUT, "> /dev/null") || die "can't write to /dev/null: $!";
98 0           exec @cmd;
99 0           exit 1;
100             }
101              
102 0     0 0   sub spawn_child( $self, @cmd ) {
  0            
  0            
  0            
103 0           my ($pid);
104 0 0         if( $^O =~ /mswin/i ) {
105 0           $pid = $self->spawn_child_win32(@cmd)
106             } else {
107 0           $pid = $self->spawn_child_posix(@cmd)
108             };
109              
110 0           return $pid
111             }
112              
113 0     0 0   sub launch( $self ) {
  0            
  0            
114 0 0         if( !$self->pid ) {
115 0           my $cmdline= join " ", $self->cmdline; # well, for Windows...
116             #warn $cmdline;
117 0 0         my $pid= $self->spawn_child( $self->cmdline )
118             or croak "Couldn't launch [$cmdline]: $!/$^E";
119 0           $self->pid( $pid );
120 0           sleep 2; # Java...
121             };
122             }
123              
124             sub url {
125             # Should return URI instead
126 0     0 0   my( $self, $type )= @_;
127 0   0       $type||= 'text';
128              
129             my $url= {
130             text => 'rmeta',
131             test => 'tika', # but GET instead of PUT
132             meta => 'rmeta',
133             #all => 'all',
134             language => 'language/string',
135             all => 'rmeta',
136             # unpack
137 0           }->{ $type };
138              
139 0           sprintf
140             'http://127.0.0.1:%s/%s',
141             $self->port,
142             $url
143             };
144              
145              
146 0     0 0   sub await($) {
  0            
147 0           my $promise = $_[0];
148 0           my @res;
149 0 0         if( $promise->is_unfulfilled ) {
150 0           require AnyEvent;
151 0           my $await = AnyEvent->condvar;
152 0     0     $promise->then(sub{ $await->send(@_)});
  0            
153 0           @res = $await->recv;
154             } else {
155 0           @res = @{ $promise->result }
  0            
156             }
157             @res
158 0           };
159              
160             # /rmeta
161             # /unpacker
162             # /all
163             # /tika
164             # /language
165             # hello world
166             sub fetch {
167 0     0 0   my( $self, %options )= @_;
168 0   0       $options{ type }||= 'text';
169 0           my $url= $self->url( $options{ type } );
170              
171 0 0 0       if(! $options{ content } and $options{ filename }) {
172             # read $options{ filename }
173             open my $fh, '<', $options{ filename }
174 0 0         or croak "Couldn't read '$options{ filename }': $!";
175 0           binmode $fh;
176 0           local $/;
177 0           $options{ content } = <$fh>;
178             };
179              
180 0           my $method;
181 0 0         if( 'test' eq $options{ type } ) {
182 0           $method= 'get';
183              
184             } else {
185 0           $method= 'put';
186             ;
187             };
188              
189 0   0       my $headers = $options{ headers } || {};
190              
191             my ($code,$res) = await
192 0           $self->ua->request( $method, $url, $options{ content }, %$headers );
193 0           my $info;
194 0 0 0       if( 'all' eq $options{ type }
      0        
195             or 'text' eq $options{ type }
196             or 'meta' eq $options{ type } ) {
197 0 0         if( $code !~ /^2..$/ ) {
198 0           croak "Got HTTP error code $code for '$options{ filename }'";
199             };
200 0           my $item = $res->[0];
201              
202             # Should/could this be lazy?
203 0           my $c = delete $item->{'X-TIKA:content'};
204             # Ghetto-strip HTML we don't want:
205 0 0 0       if( $c =~ m!(.*)!s or $c =~ m!!) {
206 0           $c = $1;
207              
208 0 0 0       if( $item->{"Content-Type"} and $item->{"Content-Type"} =~ m!^text/plain\b!) {
209             # Also strip the enclosing

..

210 0           $c =~ s!\A\s*

(.*)\s*

\s*\z!$1!s;
211             };
212             } else {
213 0           warn "Couldn't find HTML body in response: $c";
214             };
215              
216 0           $info= Apache::Tika::DocInfo->new({
217             content => $c,
218             meta => $item,
219             });
220              
221 0 0         if( ! defined $info->{meta}->{"meta:language"} ) {
222             # Yay. Two requests.
223 0           my $lang_meta = $self->fetch(%options, type => 'language', 'Content-Type' => $item->{'Content-Type'});
224 0           $info->{meta}->{"meta:language"} = $lang_meta->meta->{"info"};
225             };
226              
227             } else {
228             # Must be '/language'
229 0 0         if( $code !~ /^2..$/ ) {
230 0           croak "Got HTTP error code $code";
231             };
232 0 0         if( ref $res ) {
233 0           $res = $res->[0];
234             } else {
235 0           $res = { info => $res };
236             };
237              
238 0           my $c = delete $res->{'X-TIKA:content'};
239 0           $info= Apache::Tika::DocInfo->new({
240             meta => $res,
241             content => undef,
242             });
243             };
244 0           $info
245             }
246              
247             sub DEMOLISH {
248 0 0 0 0 0   kill -9 => $_[0]->pid
249             if( $_[0] and $_[0]->pid );
250             }
251              
252             __PACKAGE__->meta->make_immutable;
253              
254             1;
255              
256             =head1 REPOSITORY
257              
258             The public repository of this module is
259             L.
260              
261             =head1 SUPPORT
262              
263             The public support forum of this module is
264             L.
265              
266             =head1 BUG TRACKER
267              
268             Please report bugs in this module via the RT CPAN bug queue at
269             L
270             or via mail to L.
271              
272             =head1 AUTHOR
273              
274             Max Maischein C
275              
276             =head1 COPYRIGHT (c)
277              
278             Copyright 2014-2019 by Max Maischein C.
279              
280             =head1 LICENSE
281              
282             This module is released under the same terms as Perl itself.
283              
284             =cut