File Coverage

blib/lib/Apache/Tika/Server.pm
Criterion Covered Total %
statement 24 115 20.8
branch 0 42 0.0
condition 0 24 0.0
subroutine 8 18 44.4
pod 0 9 0.0
total 32 208 15.3


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

..

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

(.*)\s*

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