Passed
Push — master ( 23b5cc...9353aa )
by Sébastien
04:46
created

Protocol::createSimpleHandler()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 29
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 12.582

Importance

Changes 0
Metric Value
cc 4
eloc 21
nc 8
nop 1
dl 0
loc 29
ccs 3
cts 16
cp 0.1875
crap 12.582
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * soluble-japha / PHPJavaBridge driver client.
7
 *
8
 * Refactored version of phpjababridge's Java.inc file compatible
9
 * with php java bridge 6.2
10
 *
11
 *
12
 * @credits   http://php-java-bridge.sourceforge.net/pjb/
13
 *
14
 * @see      http://github.com/belgattitude/soluble-japha
15
 *
16
 * @author Jost Boekemeier
17
 * @author Vanvelthem Sébastien (refactoring and fixes from original implementation)
18
 * @license   MIT
19
 *
20
 * The MIT License (MIT)
21
 * Copyright (c) 2014-2017 Jost Boekemeier
22
 * Permission is hereby granted, free of charge, to any person obtaining a copy
23
 * of this software and associated documentation files (the "Software"), to deal
24
 * in the Software without restriction, including without limitation the rights
25
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26
 * copies of the Software, and to permit persons to whom the Software is
27
 * furnished to do so, subject to the following conditions:
28
 *
29
 * The above copyright notice and this permission notice shall be included in
30
 * all copies or substantial portions of the Software.
31
 *
32
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38
 * THE SOFTWARE.
39
 */
40
41
namespace Soluble\Japha\Bridge\Driver\Pjb62;
42
43
use Soluble\Japha\Bridge\Driver\Pjb62\Exception\BrokenConnectionException;
44
use Soluble\Japha\Bridge\Exception\ConnectionException;
45
46
class Protocol
47
{
48
    /**
49
     * @var Client
50
     */
51
    public $client;
52
53
    /**
54
     * @var string|null
55
     */
56
    public $webContext;
57
58
    /**
59
     * @var string
60
     */
61
    public $serverName;
62
63
    /**
64
     * @var SimpleHttpHandler|HttpTunnelHandler|SocketHandler
65
     */
66
    public $handler;
67
68
    /**
69
     * @var SocketHandler
70
     */
71
    protected $socketHandler;
72
73
    /**
74
     * @var array
75
     */
76
    protected $host;
77
78
    /**
79
     * @var string
80
     */
81
    protected $java_hosts;
82
83
    /**
84
     * @var string
85
     */
86
    protected $java_servlet;
87
88
    /**
89
     * @var int
90
     */
91
    public $java_recv_size;
92
93
    /**
94
     * @var int
95
     */
96
    public $java_send_size;
97
98
    /**
99
     * @var string
100
     */
101
    protected $internal_encoding;
102
103
    /**
104
     * @param Client $client
105
     * @param string $java_hosts
106
     * @param string $java_servlet
107
     * @param int    $java_recv_size
108
     * @param int    $java_send_size
109
     */
110 26
    public function __construct(Client $client, $java_hosts, $java_servlet, $java_recv_size, $java_send_size)
111
    {
112 26
        $this->client = $client;
113 26
        $this->internal_encoding = $client->getParam(Client::PARAM_JAVA_INTERNAL_ENCODING);
114 26
        $this->java_hosts = $java_hosts;
115 26
        $this->java_servlet = $java_servlet;
116 26
        $this->java_recv_size = $java_recv_size;
117 26
        $this->java_send_size = $java_send_size;
118 26
        $this->setHost($java_hosts);
119 26
        $this->handler = $this->createHandler();
120 24
    }
121
122
    /**
123
     * @return Client
124
     */
125 26
    public function getClient(): Client
126
    {
127 26
        return $this->client;
128
    }
129
130
    /**
131
     * @return string
132
     */
133 26
    public function getOverrideHosts(): string
134
    {
135 26
        if (array_key_exists('X_JAVABRIDGE_OVERRIDE_HOSTS', $_ENV)) {
136
            $override = $_ENV['X_JAVABRIDGE_OVERRIDE_HOSTS'];
137
            if (null !== $override && $override !== '/') {
138
                return $override;
139
            }
140
        }
141
142 26
        return Pjb62Driver::getJavaBridgeHeader('X_JAVABRIDGE_OVERRIDE_HOSTS_REDIRECT', $_SERVER);
143
    }
144
145 8
    public function setSocketHandler(SocketHandler $socketHandler): void
146
    {
147 8
        $this->socketHandler = $socketHandler;
148 8
    }
149
150 8
    /**
151
     * @throws BrokenConnectionException
152 8
     */
153
    public function getSocketHandler(): SocketHandler
154
    {
155
        if ($this->socketHandler === null) {
156 8
            throw new BrokenConnectionException('No SocketHandler defined');
157
        }
158
159
        return $this->socketHandler;
160
    }
161
162 26
    /**
163
     * @param string $java_hosts
164 26
     */
165
    public function setHost(string $java_hosts): void
166 26
    {
167 26
        $hosts = explode(';', $java_hosts);
168 26
        //$hosts = explode(";", JAVA_HOSTS);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
169
        $host = explode(':', $hosts[0]);
170 26
        while (count($host) < 3) {
171
            array_unshift($host, '');
172
        }
173 26
        if (substr($host[1], 0, 2) === '//') {
174 26
            $host[1] = substr($host[1], 2);
175
        }
176
        $this->host = $host;
177
    }
178
179 26
    /**
180
     * @return array
181 26
     */
182
    public function getHost(): array
183
    {
184
        return $this->host;
185
    }
186
187 26
    /**
188
     * @return SimpleHttpHandler|HttpTunnelHandler
189 26
     */
190 26
    public function createHttpHandler()
191 26
    {
192
        $overrideHosts = $this->getOverrideHosts();
193
        $ssl = '';
194
        if ($overrideHosts) {
195
            $s = $overrideHosts;
196
            if ((strlen($s) > 2) && ($s[1] === ':')) {
197
                if ($s[0] === 's') {
198
                    $ssl = 'ssl://';
199
                }
200
                $s = substr($s, 2);
201
            }
202
            $webCtx = strpos($s, '//');
203
            if ($webCtx) {
204
                $host = substr($s, 0, $webCtx);
205
            } else {
206
                $host = $s;
207
            }
208
            $idx = strpos($host, ':');
209
            if ($idx) {
210
                if ($webCtx) {
211
                    $port = substr($host, $idx + 1, $webCtx);
212
                } else {
213
                    $port = substr($host, $idx + 1);
214
                }
215
                $host = substr($host, 0, $idx);
216
            } else {
217
                $port = '8080';
218
            }
219
            if ($webCtx) {
220
                $webCtx = substr($s, $webCtx + 1);
221 26
            }
222 26
            $this->webContext = $webCtx;
223
        } else {
224
            $hostVec = $this->getHost();
225 26
            if ($ssl = $hostVec[0]) {
226 26
                $ssl .= '://';
227
            }
228
            $host = $hostVec[1];
229
            $port = $hostVec[2];
230 26
        }
231 26
        $this->serverName = "${ssl}${host}:$port";
232
233
        if ((array_key_exists('X_JAVABRIDGE_REDIRECT', $_SERVER)) ||
234
                (array_key_exists('HTTP_X_JAVABRIDGE_REDIRECT', $_SERVER))) {
235 26
            return new SimpleHttpHandler($this, $ssl, $host, $port, $this->java_servlet, $this->java_recv_size, $this->java_send_size);
236
        }
237
238
        return new HttpTunnelHandler($this, $ssl, $host, $port, $this->java_servlet, $this->java_recv_size, $this->java_send_size);
239
    }
240
241
    /**
242
     * @param string $channelName With format <host:port>. If host is omitted, '127.0.0.1' by default
243
     *
244
     * @throws ConnectionException
245
     * @throws Exception\IOException
246
     */
247
    public function createSimpleHandler(string $channelName): SocketHandler
248
    {
249
        if (is_numeric($channelName)) {
0 ignored issues
show
introduced by
The condition is_numeric($channelName) can never be true.
Loading history...
250
            $host = '127.0.0.1';
251
            $port = $channelName;
252
        } else {
253
            list($host, $port) = explode(':', $channelName);
254
        }
255
        $timeout = in_array($host, ['localhost', '127.0.0.1']) ? 5 : 20;
256
        $peer = pfsockopen($host, $port, $errno, $errstr, $timeout);
257
        if (!$peer) {
0 ignored issues
show
introduced by
The condition ! $peer can never be false.
Loading history...
258
            throw new ConnectionException(
259
                sprintf(
260
                    'No Java server at %s:%s. Error message: %s (errno: %s)',
261
                    $host,
262
                    $port,
263
                    $errstr,
264
                    $errno
265
                )
266
            );
267
        }
268
269 26
        stream_set_timeout($peer, -1);
270 26
        $handler = new SocketHandler($this, new SocketChannelP($peer, $host, $this->java_recv_size, $this->java_send_size));
271
        $compatibility = PjbProxyClient::getInstance()->getCompatibilityOption($this->client);
272 26
        $this->write("\177$compatibility");
273
        $this->serverName = "$host:$port";
274
275
        return $handler;
276
    }
277
278 26
    public function java_get_simple_channel(): ?string
279
    {
280 26
        $java_hosts = $this->java_hosts;
281
        $java_servlet = $this->java_servlet;
282
283 26
        return ($java_hosts && (!$java_servlet || ($java_servlet === 'Off'))) ? $java_hosts : null;
284
    }
285
286
    public function createHandler()
287
    {
288
        if (!Pjb62Driver::getJavaBridgeHeader('X_JAVABRIDGE_OVERRIDE_HOSTS', $_SERVER) &&
289 113
                //((function_exists('java_get_default_channel') && ($defaultChannel = java_get_default_channel())) ||
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
290 113
                ($defaultChannel = $this->java_get_simple_channel())) {
291
            return $this->createSimpleHandler($defaultChannel);
292
        } else {
293
            return $this->createHttpHandler();
294
        }
295
    }
296
297 114
    public function redirect(): void
298
    {
299
        $this->handler->redirect();
300
    }
301
302 129
    /**
303 129
     * @return string
304 129
     */
305
    public function read(int $size): string
306 129
    {
307
        return $this->handler->read($size);
308
    }
309
310 129
    public function sendData(): void
311 129
    {
312
        if ($this->client->sendBuffer !== null) {
313
            $this->handler->write($this->client->sendBuffer);
314
            $this->client->sendBuffer = null;
315 20
        }
316
    }
317
318
    public function flush(): void
319
    {
320 20
        $this->sendData();
321 7
    }
322
323
    public function getKeepAlive(): string
324
    {
325 114
        return $this->handler->getKeepAlive();
326 113
    }
327
328
    public function keepAlive(): void
329
    {
330
        $this->handler->keepAlive();
331
    }
332
333 114
    public function handle(): void
334 114
    {
335
        $this->client->handleRequests();
336
    }
337
338 114
    /**
339 114
     * @param string $data
340 113
     */
341 113
    public function write($data): void
342
    {
343
        $this->client->sendBuffer .= $data;
344
    }
345
346
    public function finish(): void
347
    {
348
        $this->flush();
349 24
        $this->handle();
350 24
        $this->redirect();
351 24
    }
352 24
353 24
    /*
354 24
     * @param string $name java class name, i.e java.math.BigInteger
355 24
     */
356
357
    public function referenceBegin($name): void
358
    {
359 24
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
360 24
        $this->client->preparedToSendBuffer = null;
361 24
        $signature = sprintf('<H p="1" v="%s">', $name);
362 24
        $this->write($signature);
363 24
        $signature[6] = '2';
364 24
        $this->client->currentArgumentsFormat = $signature;
365
    }
366
367
    public function referenceEnd(): void
368
    {
369
        $format = '</H>';
370
        $this->client->currentArgumentsFormat .= $format;
371 72
        $this->write($format);
372 72
        $this->finish();
373 72
        $this->client->currentCacheKey = null;
374 72
    }
375 72
376 72
    /**
377 72
     * @param string $name java class name i.e java.math.BigInteger
378
     */
379
    public function createObjectBegin($name): void
380
    {
381 72
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
382 72
        $this->client->preparedToSendBuffer = null;
383 72
        $signature = sprintf('<K p="1" v="%s">', $name);
384 72
        $this->write($signature);
385 71
        $signature[6] = '2';
386 71
        $this->client->currentArgumentsFormat = $signature;
387
    }
388
389
    public function createObjectEnd(): void
390
    {
391
        $format = '</K>';
392
        $this->client->currentArgumentsFormat .= $format;
393
        $this->write($format);
394 24
        $this->finish();
395 24
        $this->client->currentCacheKey = null;
396 24
    }
397 24
398 24
    /**
399
     * @param int    $object object id
400
     * @param string $method method name
401
     */
402 24
    public function propertyAccessBegin($object, $method): void
403 24
    {
404 24
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
405 24
        $this->client->preparedToSendBuffer = null;
406 24
        $this->write(sprintf('<G p="1" v="%x" m="%s">', $object, $method));
407 24
        $this->client->currentArgumentsFormat = "<G p=\"2\" v=\"%x\" m=\"${method}\">";
408
    }
409
410
    public function propertyAccessEnd(): void
411
    {
412
        $format = '</G>';
413
        $this->client->currentArgumentsFormat .= $format;
414
        $this->write($format);
415 106
        $this->finish();
416 106
        $this->client->currentCacheKey = null;
417 106
    }
418 106
419 106
    /**
420
     * @param int    $object_id object id
421
     * @param string $method    method name
422
     */
423 106
    public function invokeBegin($object_id, $method): void
424 106
    {
425 106
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
426 106
        $this->client->preparedToSendBuffer = null;
427 106
        $this->write(sprintf('<Y p="1" v="%x" m="%s">', $object_id, $method));
428 106
        $this->client->currentArgumentsFormat = "<Y p=\"2\" v=\"%x\" m=\"${method}\">";
429
    }
430
431
    public function invokeEnd(): void
432
    {
433
        $format = '</Y>';
434
        $this->client->currentArgumentsFormat .= $format;
435
        $this->write($format);
436
        $this->finish();
437
        $this->client->currentCacheKey = null;
438
    }
439
440
    public function resultBegin(): void
441
    {
442
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
443
        $this->client->preparedToSendBuffer = null;
444
        $this->write('<R>');
445
    }
446
447
    public function resultEnd(): void
448
    {
449 85
        $this->client->currentCacheKey = null;
450 85
        $this->write('</R>');
451 85
        $this->flush();
452 85
    }
453
454
    /**
455
     * @param string $name
456
     */
457
    public function writeString($name): void
458
    {
459 3
        $format = '<S v="%s"/>';
460 3
        $this->client->currentArgumentsFormat .= $format;
461 3
        $this->write(sprintf($format, htmlspecialchars($name, ENT_COMPAT, $this->internal_encoding)));
462 3
    }
463
464
    /**
465
     * @param bool $boolean
466
     */
467
    public function writeBoolean($boolean): void
468
    {
469 25
        $format = '<T v="%s"/>';
470 25
        $this->client->currentArgumentsFormat .= $format;
471
        $this->write(sprintf($format, $boolean));
472
    }
473 25
474
    /**
475 25
     * @param int $l
476
     */
477
    public function writeLong($l): void
478
    {
479
        $this->client->currentArgumentsFormat .= '<J v="%d"/>';
480
        if ($l < 0) {
481
            $this->write(sprintf('<L v="%x" p="A"/>', -$l));
482
        } else {
483
            $this->write(sprintf('<L v="%x" p="O"/>', $l));
484
        }
485
    }
486
487
    /**
488
     * @param mixed $l
489
     */
490
    public function writeULong($l): void
491
    {
492 4
        $format = '<L v="%x" p="O"/>';
493 4
        $this->client->currentArgumentsFormat .= $format;
494 4
        $this->write(sprintf($format, $l));
495 4
    }
496
497
    /**
498
     * @param float $d
499
     */
500
    public function writeDouble($d): void
501
    {
502 98
        $format = '<D v="%.14e"/>';
503 98
        $this->client->currentArgumentsFormat .= $format;
504 98
        $this->write(sprintf($format, $d));
505 98
    }
506
507
    /**
508
     * @param string|int|null $object
509
     */
510
    public function writeObject($object): void
511
    {
512
        $format = '<O v="%x"/>';
513
        $this->client->currentArgumentsFormat .= $format;
514
        $this->write(sprintf($format, $object));
515
    }
516
517
    /**
518 1
     * @param int    $object
519 1
     * @param string $str
520
     */
521
    public function writeException($object, $str): void
522
    {
523 13
        $this->write(sprintf('<E v="%x" m="%s"/>', $object, htmlspecialchars($str, ENT_COMPAT, $this->internal_encoding)));
524 13
    }
525
526
    public function writeCompositeBegin_a(): void
527
    {
528 14
        $this->write('<X t="A">');
529 14
    }
530
531
    public function writeCompositeBegin_h(): void
532
    {
533
        $this->write('<X t="H">');
534
    }
535
536 10
    public function writeCompositeEnd(): void
537 10
    {
538
        $this->write('</X>');
539
    }
540
541
    /**
542
     * @param string $key
543
     */
544 7
    public function writePairBegin_s($key): void
545 7
    {
546
        $this->write(sprintf('<P t="S" v="%s">', htmlspecialchars($key, ENT_COMPAT, 'ISO-8859-1')));
547
    }
548
549
    /**
550
     * @param int $key
551
     */
552
    public function writePairBegin_n($key): void
553
    {
554 13
        $this->write(sprintf('<P t="N" v="%x">', $key));
555 13
    }
556
557
    public function writePairBegin(): void
558
    {
559
        $this->write('<P>');
560
    }
561
562 107
    public function writePairEnd(): void
563 107
    {
564 107
        $this->write('</P>');
565 107
    }
566
567
    /**
568
     * @param int $object
569
     */
570
    public function writeUnref($object): void
571
    {
572 1
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
573
        $this->client->preparedToSendBuffer = null;
574
        $this->write(sprintf('<U v="%x"/>', $object));
575
    }
576
577
    /**
578
     * @return string
579
     */
580
    public function getServerName(): string
581
    {
582
        return $this->serverName;
583
    }
584
585
    /**
586
     * @param int $code
587
     */
588
    public function writeExitCode($code): void
589
    {
590
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
591
        $this->client->preparedToSendBuffer = null;
592
        $this->write(sprintf('<Z v="%x"/>', 0xffffffff & $code));
593
    }
594
}
595