Protocol   F
last analyzed

Complexity

Total Complexity 75

Size/Duplication

Total Lines 554
Duplicated Lines 0 %

Test Coverage

Coverage 70.72%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 200
c 2
b 1
f 0
dl 0
loc 554
ccs 186
cts 263
cp 0.7072
rs 2.4
wmc 75

47 Methods

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

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