Passed
Push — master ( 550b9e...103607 )
by Sébastien
09:49 queued 07:35
created

Protocol   F

Complexity

Total Complexity 75

Size/Duplication

Total Lines 553
Duplicated Lines 0 %

Test Coverage

Coverage 70.72%

Importance

Changes 0
Metric Value
eloc 200
dl 0
loc 553
ccs 186
cts 263
cp 0.7072
rs 2.4
c 0
b 0
f 0
wmc 75

47 Methods

Rating   Name   Duplication   Size   Complexity  
A createObjectBegin() 0 8 1
A createObjectEnd() 0 7 1
A sendData() 0 5 2
A propertyAccessEnd() 0 7 1
A writePairBegin_n() 0 3 1
A setSocketHandler() 0 3 1
A referenceBegin() 0 8 1
A writePairBegin() 0 3 1
A writeDouble() 0 5 1
A writeBoolean() 0 5 1
A getClient() 0 3 1
A writeExitCode() 0 5 1
A writeCompositeBegin_h() 0 3 1
A getKeepAlive() 0 3 1
A resultEnd() 0 5 1
A writeException() 0 3 1
A getServerName() 0 3 1
A redirect() 0 3 1
A __construct() 0 10 1
A writePairEnd() 0 3 1
A invokeBegin() 0 6 1
A writePairBegin_s() 0 3 1
A writeLong() 0 7 2
A getOverrideHosts() 0 10 4
A getHost() 0 3 1
A read() 0 3 1
A keepAlive() 0 3 1
A createSimpleHandler() 0 29 4
A java_get_simple_channel() 0 6 4
A referenceEnd() 0 7 1
A createHandler() 0 8 3
A finish() 0 5 1
A writeUnref() 0 5 1
A resultBegin() 0 5 1
C createHttpHandler() 0 54 13
A handle() 0 3 1
A propertyAccessBegin() 0 6 1
A invokeEnd() 0 7 1
A flush() 0 3 1
A writeObject() 0 5 1
A writeCompositeEnd() 0 3 1
A getSocketHandler() 0 7 2
A setHost() 0 12 3
A writeCompositeBegin_a() 0 3 1
A writeULong() 0 5 1
A write() 0 3 1
A writeString() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like Protocol often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Protocol, and based on these observations, apply Extract Interface, too.

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\ConfigurationException;
45
use Soluble\Japha\Bridge\Exception\ConnectionException;
46
47
class Protocol
48
{
49
    /**
50
     * @var Client
51
     */
52
    public $client;
53
54
    /**
55
     * @var string|null
56
     */
57
    public $webContext;
58
59
    /**
60
     * @var string
61
     */
62
    public $serverName;
63
64
    /**
65
     * @var SimpleHttpHandler|HttpTunnelHandler|SocketHandler
66
     */
67
    public $handler;
68
69
    /**
70
     * @var SocketHandler
71
     */
72
    protected $socketHandler;
73
74
    /**
75
     * @var array
76
     */
77
    protected $host;
78
79
    /**
80
     * @var string
81
     */
82
    protected $java_hosts;
83
84
    /**
85
     * @var string
86
     */
87
    protected $java_servlet;
88
89
    /**
90
     * @var int
91
     */
92
    public $java_recv_size;
93
94
    /**
95
     * @var int
96
     */
97
    public $java_send_size;
98
99
    /**
100
     * @var string
101
     */
102
    protected $internal_encoding;
103
104
    /**
105
     * @param Client $client
106
     * @param string $java_hosts
107
     * @param string $java_servlet
108
     * @param int    $java_recv_size
109
     * @param int    $java_send_size
110
     */
111 28
    public function __construct(Client $client, $java_hosts, $java_servlet, $java_recv_size, $java_send_size)
112
    {
113 28
        $this->client = $client;
114 28
        $this->internal_encoding = $client->getParam(Client::PARAM_JAVA_INTERNAL_ENCODING);
115 28
        $this->java_hosts = $java_hosts;
116 28
        $this->java_servlet = $java_servlet;
117 28
        $this->java_recv_size = $java_recv_size;
118 28
        $this->java_send_size = $java_send_size;
119 28
        $this->setHost($java_hosts);
120 28
        $this->handler = $this->createHandler();
121 26
    }
122
123
    /**
124
     * @return Client
125
     */
126 28
    public function getClient(): Client
127
    {
128 28
        return $this->client;
129
    }
130
131
    /**
132
     * @return string
133
     */
134 28
    public function getOverrideHosts(): string
135
    {
136 28
        if (array_key_exists('X_JAVABRIDGE_OVERRIDE_HOSTS', $_ENV)) {
137
            $override = $_ENV['X_JAVABRIDGE_OVERRIDE_HOSTS'];
138
            if (null !== $override && $override !== '/') {
139
                return $override;
140
            }
141
        }
142
143 28
        return Pjb62Driver::getJavaBridgeHeader('X_JAVABRIDGE_OVERRIDE_HOSTS_REDIRECT', $_SERVER);
144
    }
145
146 7
    public function setSocketHandler(SocketHandler $socketHandler): void
147
    {
148 7
        $this->socketHandler = $socketHandler;
149 7
    }
150
151
    /**
152
     * @throws BrokenConnectionException
153
     */
154 7
    public function getSocketHandler(): SocketHandler
155
    {
156 7
        if ($this->socketHandler === null) {
157
            throw new BrokenConnectionException('No SocketHandler defined');
158
        }
159
160 7
        return $this->socketHandler;
161
    }
162
163
    /**
164
     * @param string $java_hosts
165
     */
166 28
    public function setHost(string $java_hosts): void
167
    {
168 28
        $hosts = explode(';', $java_hosts);
169
        //$hosts = explode(";", JAVA_HOSTS);
170 28
        $host = explode(':', $hosts[0]);
171 28
        while (count($host) < 3) {
172 28
            array_unshift($host, '');
173
        }
174 28
        if (substr($host[1], 0, 2) === '//') {
175
            $host[1] = substr($host[1], 2);
176
        }
177 28
        $this->host = $host;
178 28
    }
179
180
    /**
181
     * @return array
182
     */
183 28
    public function getHost(): array
184
    {
185 28
        return $this->host;
186
    }
187
188
    /**
189
     * @return HttpTunnelHandler|SimpleHttpHandler
190
     * @throws Exception\IllegalStateException
191
     */
192 28
    public function createHttpHandler()
193
    {
194 28
        $overrideHosts = $this->getOverrideHosts();
195 28
        $ssl = '';
196 28
        if ($overrideHosts) {
197
            $s = $overrideHosts;
198
            if ((strlen($s) > 2) && ($s[1] === ':')) {
199
                if ($s[0] === 's') {
200
                    $ssl = 'ssl://';
201
                }
202
                $s = substr($s, 2);
203
            }
204
            $webCtx = strpos($s, '//');
205
            if ($webCtx) {
206
                $host = substr($s, 0, $webCtx);
207
            } else {
208
                $host = $s;
209
            }
210
            $idx = strpos($host, ':');
211
            if ($idx) {
212
                if ($webCtx) {
213
                    $port = substr($host, $idx + 1, $webCtx);
214
                } else {
215
                    $port = substr($host, $idx + 1);
216
                }
217
                $host = substr($host, 0, $idx);
218
            } else {
219
                $port = '8080';
220
            }
221
            if ($webCtx) {
222
                $webCtx = substr($s, $webCtx + 1);
223
            }
224
            if (!is_string($webCtx)) {
225
                throw new ConfigurationException(
226
                    'Cannot get a valid context'
227
                );
228
            }
229
            $this->webContext = $webCtx;
230
        } else {
231 28
            $hostVec = $this->getHost();
232 28
            if ($ssl = $hostVec[0]) {
233
                $ssl .= '://';
234
            }
235 28
            $host = $hostVec[1];
236 28
            $port = $hostVec[2];
237
        }
238 28
        $this->serverName = "${ssl}${host}:$port";
239
240 28
        if ((array_key_exists('X_JAVABRIDGE_REDIRECT', $_SERVER)) ||
241 28
                (array_key_exists('HTTP_X_JAVABRIDGE_REDIRECT', $_SERVER))) {
242
            return new SimpleHttpHandler($this, $ssl, $host, $port, $this->java_servlet, $this->java_recv_size, $this->java_send_size);
243
        }
244
245 28
        return new HttpTunnelHandler($this, $ssl, $host, $port, $this->java_servlet, $this->java_recv_size, $this->java_send_size);
246
    }
247
248
    /**
249
     * @param string $channelName With format <host:port>. If host is omitted, '127.0.0.1' by default
250
     *
251
     * @throws ConnectionException
252
     * @throws Exception\IOException
253
     */
254
    public function createSimpleHandler(string $channelName): SocketHandler
255
    {
256
        if (is_numeric($channelName)) {
257
            $host = '127.0.0.1';
258
            $port = $channelName;
259
        } else {
260
            list($host, $port) = explode(':', $channelName);
261
        }
262
        $timeout = in_array($host, ['localhost', '127.0.0.1']) ? 5 : 20;
263
        $peer = pfsockopen($host, (int) $port, $errno, $errstr, $timeout);
264
        if (!\is_resource($peer)) {
265
            throw new ConnectionException(
266
                sprintf(
267
                    'No Java server at %s:%s. Error message: %s (errno: %s)',
268
                    $host,
269
                    $port,
270
                    $errstr,
271
                    $errno
272
                )
273
            );
274
        }
275
276
        stream_set_timeout($peer, -1);
277
        $handler = new SocketHandler($this, new SocketChannelP($peer, $host, $this->java_recv_size, $this->java_send_size));
278
        $compatibility = PjbProxyClient::getInstance()->getCompatibilityOption($this->client);
279
        $this->write("\177$compatibility");
280
        $this->serverName = "$host:$port";
281
282
        return $handler;
283
    }
284
285 28
    public function java_get_simple_channel(): ?string
286
    {
287 28
        $java_hosts = $this->java_hosts;
288 28
        $java_servlet = $this->java_servlet;
289
290 28
        return ($java_hosts && (!$java_servlet || ($java_servlet === 'Off'))) ? $java_hosts : null;
291
    }
292
293 28
    public function createHandler()
294
    {
295 28
        if (!Pjb62Driver::getJavaBridgeHeader('X_JAVABRIDGE_OVERRIDE_HOSTS', $_SERVER) &&
296
                //((function_exists('java_get_default_channel') && ($defaultChannel = java_get_default_channel())) ||
297 28
                ($defaultChannel = $this->java_get_simple_channel())) {
298
            return $this->createSimpleHandler($defaultChannel);
299
        } else {
300 28
            return $this->createHttpHandler();
301
        }
302
    }
303
304 107
    public function redirect(): void
305
    {
306 107
        $this->handler->redirect();
307 107
    }
308
309
    /**
310
     * @return string
311
     */
312 108
    public function read(int $size): string
313
    {
314 108
        return $this->handler->read($size);
315
    }
316
317 126
    public function sendData(): void
318
    {
319 126
        if ($this->client->sendBuffer !== null) {
320 126
            $this->handler->write($this->client->sendBuffer);
321 126
            $this->client->sendBuffer = null;
322
        }
323 126
    }
324
325 126
    public function flush(): void
326
    {
327 126
        $this->sendData();
328 126
    }
329
330 22
    public function getKeepAlive(): string
331
    {
332 22
        return $this->handler->getKeepAlive();
333
    }
334
335 22
    public function keepAlive(): void
336
    {
337 22
        $this->handler->keepAlive();
338 7
    }
339
340 108
    public function handle(): void
341
    {
342 108
        $this->client->handleRequests();
343 107
    }
344
345
    /**
346
     * @param string $data
347
     */
348 108
    public function write($data): void
349
    {
350 108
        $this->client->sendBuffer .= $data;
351 108
    }
352
353 108
    public function finish(): void
354
    {
355 108
        $this->flush();
356 108
        $this->handle();
357 107
        $this->redirect();
358 107
    }
359
360
    /*
361
     * @param string $name java class name, i.e java.math.BigInteger
362
     */
363
364 23
    public function referenceBegin($name): void
365
    {
366 23
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
367 23
        $this->client->preparedToSendBuffer = null;
368 23
        $signature = sprintf('<H p="1" v="%s">', $name);
369 23
        $this->write($signature);
370 23
        $signature[6] = '2';
371 23
        $this->client->currentArgumentsFormat = $signature;
372 23
    }
373
374 23
    public function referenceEnd(): void
375
    {
376 23
        $format = '</H>';
377 23
        $this->client->currentArgumentsFormat .= $format;
378 23
        $this->write($format);
379 23
        $this->finish();
380 23
        $this->client->currentCacheKey = null;
381 23
    }
382
383
    /**
384
     * @param string $name java class name i.e java.math.BigInteger
385
     */
386 67
    public function createObjectBegin($name): void
387
    {
388 67
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
389 67
        $this->client->preparedToSendBuffer = null;
390 67
        $signature = sprintf('<K p="1" v="%s">', $name);
391 67
        $this->write($signature);
392 67
        $signature[6] = '2';
393 67
        $this->client->currentArgumentsFormat = $signature;
394 67
    }
395
396 67
    public function createObjectEnd(): void
397
    {
398 67
        $format = '</K>';
399 67
        $this->client->currentArgumentsFormat .= $format;
400 67
        $this->write($format);
401 67
        $this->finish();
402 66
        $this->client->currentCacheKey = null;
403 66
    }
404
405
    /**
406
     * @param int    $object object id
407
     * @param string $method method name
408
     */
409 18
    public function propertyAccessBegin($object, $method): void
410
    {
411 18
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
412 18
        $this->client->preparedToSendBuffer = null;
413 18
        $this->write(sprintf('<G p="1" v="%x" m="%s">', $object, $method));
414 18
        $this->client->currentArgumentsFormat = "<G p=\"2\" v=\"%x\" m=\"${method}\">";
415 18
    }
416
417 18
    public function propertyAccessEnd(): void
418
    {
419 18
        $format = '</G>';
420 18
        $this->client->currentArgumentsFormat .= $format;
421 18
        $this->write($format);
422 18
        $this->finish();
423 18
        $this->client->currentCacheKey = null;
424 18
    }
425
426
    /**
427
     * @param int    $object_id object id
428
     * @param string $method    method name
429
     */
430 100
    public function invokeBegin($object_id, $method): void
431
    {
432 100
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
433 100
        $this->client->preparedToSendBuffer = null;
434 100
        $this->write(sprintf('<Y p="1" v="%x" m="%s">', $object_id, $method));
435 100
        $this->client->currentArgumentsFormat = "<Y p=\"2\" v=\"%x\" m=\"${method}\">";
436 100
    }
437
438 100
    public function invokeEnd(): void
439
    {
440 100
        $format = '</Y>';
441 100
        $this->client->currentArgumentsFormat .= $format;
442 100
        $this->write($format);
443 100
        $this->finish();
444 100
        $this->client->currentCacheKey = null;
445 100
    }
446
447
    public function resultBegin(): void
448
    {
449
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
450
        $this->client->preparedToSendBuffer = null;
451
        $this->write('<R>');
452
    }
453
454
    public function resultEnd(): void
455
    {
456
        $this->client->currentCacheKey = null;
457
        $this->write('</R>');
458
        $this->flush();
459
    }
460
461
    /**
462
     * @param string $name
463
     */
464 79
    public function writeString($name): void
465
    {
466 79
        $format = '<S v="%s"/>';
467 79
        $this->client->currentArgumentsFormat .= $format;
468 79
        $this->write(sprintf($format, htmlspecialchars($name, ENT_COMPAT, $this->internal_encoding)));
469 79
    }
470
471
    /**
472
     * @param bool $boolean
473
     */
474 3
    public function writeBoolean($boolean): void
475
    {
476 3
        $format = '<T v="%s"/>';
477 3
        $this->client->currentArgumentsFormat .= $format;
478 3
        $this->write(sprintf($format, $boolean));
479 3
    }
480
481
    /**
482
     * @param int $l
483
     */
484 25
    public function writeLong($l): void
485
    {
486 25
        $this->client->currentArgumentsFormat .= '<J v="%d"/>';
487 25
        if ($l < 0) {
488
            $this->write(sprintf('<L v="%x" p="A"/>', -$l));
489
        } else {
490 25
            $this->write(sprintf('<L v="%x" p="O"/>', $l));
491
        }
492 25
    }
493
494
    /**
495
     * @param mixed $l
496
     */
497
    public function writeULong($l): void
498
    {
499
        $format = '<L v="%x" p="O"/>';
500
        $this->client->currentArgumentsFormat .= $format;
501
        $this->write(sprintf($format, $l));
502
    }
503
504
    /**
505
     * @param float $d
506
     */
507 4
    public function writeDouble($d): void
508
    {
509 4
        $format = '<D v="%.14e"/>';
510 4
        $this->client->currentArgumentsFormat .= $format;
511 4
        $this->write(sprintf($format, $d));
512 4
    }
513
514
    /**
515
     * @param string|int|null $object
516
     */
517 92
    public function writeObject($object): void
518
    {
519 92
        $format = '<O v="%x"/>';
520 92
        $this->client->currentArgumentsFormat .= $format;
521 92
        $this->write(sprintf($format, $object));
522 92
    }
523
524
    /**
525
     * @param int    $object
526
     * @param string $str
527
     */
528
    public function writeException($object, $str): void
529
    {
530
        $this->write(sprintf('<E v="%x" m="%s"/>', $object, htmlspecialchars($str, ENT_COMPAT, $this->internal_encoding)));
531
    }
532
533 1
    public function writeCompositeBegin_a(): void
534
    {
535 1
        $this->write('<X t="A">');
536 1
    }
537
538 13
    public function writeCompositeBegin_h(): void
539
    {
540 13
        $this->write('<X t="H">');
541 13
    }
542
543 14
    public function writeCompositeEnd(): void
544
    {
545 14
        $this->write('</X>');
546 14
    }
547
548
    /**
549
     * @param string $key
550
     */
551 10
    public function writePairBegin_s($key): void
552
    {
553 10
        $this->write(sprintf('<P t="S" v="%s">', htmlspecialchars($key, ENT_COMPAT, 'ISO-8859-1')));
554 10
    }
555
556
    /**
557
     * @param int $key
558
     */
559 7
    public function writePairBegin_n($key): void
560
    {
561 7
        $this->write(sprintf('<P t="N" v="%x">', $key));
562 7
    }
563
564
    public function writePairBegin(): void
565
    {
566
        $this->write('<P>');
567
    }
568
569 13
    public function writePairEnd(): void
570
    {
571 13
        $this->write('</P>');
572 13
    }
573
574
    /**
575
     * @param int $object
576
     */
577 101
    public function writeUnref($object): void
578
    {
579 101
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
580 101
        $this->client->preparedToSendBuffer = null;
581 101
        $this->write(sprintf('<U v="%x"/>', $object));
582 101
    }
583
584
    /**
585
     * @return string
586
     */
587 1
    public function getServerName(): string
588
    {
589 1
        return $this->serverName;
590
    }
591
592
    /**
593
     * @param int $code
594
     */
595
    public function writeExitCode($code): void
596
    {
597
        $this->client->sendBuffer .= $this->client->preparedToSendBuffer;
598
        $this->client->preparedToSendBuffer = null;
599
        $this->write(sprintf('<Z v="%x"/>', 0xffffffff & $code));
600
    }
601
}
602