Client::link()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * soluble-japha / PHPJavaBridge driver client.
6
 *
7
 * Refactored version of phpjababridge's Java.inc file compatible
8
 * with php java bridge 6.2
9
 *
10
 *
11
 * @credits   http://php-java-bridge.sourceforge.net/pjb/
12
 *
13
 * @see      http://github.com/belgattitude/soluble-japha
14
 *
15
 * @author Jost Boekemeier
16
 * @author Vanvelthem Sébastien (refactoring and fixes from original implementation)
17
 * @license   MIT
18
 *
19
 * The MIT License (MIT)
20
 * Copyright (c) 2014-2017 Jost Boekemeier
21
 * Permission is hereby granted, free of charge, to any person obtaining a copy
22
 * of this software and associated documentation files (the "Software"), to deal
23
 * in the Software without restriction, including without limitation the rights
24
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
 * copies of the Software, and to permit persons to whom the Software is
26
 * furnished to do so, subject to the following conditions:
27
 *
28
 * The above copyright notice and this permission notice shall be included in
29
 * all copies or substantial portions of the Software.
30
 *
31
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37
 * THE SOFTWARE.
38
 */
39
40
namespace Soluble\Japha\Bridge\Driver\Pjb62;
41
42
use ArrayObject;
43
use Psr\Log\LoggerInterface;
44
use Soluble\Japha\Bridge\Exception\JavaException;
45
use Soluble\Japha\Interfaces;
46
use Soluble\Japha\Bridge\Driver\Pjb62\Utils\HelperFunctions;
47
48
class Client
49
{
50
    public const PARAM_JAVA_HOSTS = 'JAVA_HOSTS';
51
    public const PARAM_JAVA_SERVLET = 'JAVA_SERVLET';
52
    public const PARAM_JAVA_AUTH_USER = 'JAVA_AUTH_USER';
53
    public const PARAM_JAVA_AUTH_PASSWORD = 'JAVA_AUTH_PASSWORD';
54
    public const PARAM_JAVA_DISABLE_AUTOLOAD = 'JAVA_DISABLE_AUTOLOAD';
55
    public const PARAM_JAVA_PREFER_VALUES = 'JAVA_PREFER_VALUES';
56
    public const PARAM_JAVA_SEND_SIZE = 'JAVA_SEND_SIZE';
57
    public const PARAM_JAVA_RECV_SIZE = 'JAVA_RECV_SIZE';
58
    public const PARAM_JAVA_LOG_LEVEL = 'JAVA_LOG_LEVEL';
59
    public const PARAM_JAVA_INTERNAL_ENCODING = 'JAVA_INTERNAL_ENCODING';
60
    public const PARAM_XML_PARSER_FORCE_SIMPLE_PARSER = 'XML_PARSER_FORCE_SIMPLE_PARSER';
61
    public const PARAM_USE_PERSISTENT_CONNECTION = 'USE_PERSISTENT_CONNECTION';
62
63
    public const DEFAULT_PARAMS = [
64
        self::PARAM_JAVA_HOSTS => 'localhost',
65
        self::PARAM_JAVA_SERVLET => 'JavaBridge/servlet.phpjavabridge',
66
        self::PARAM_JAVA_AUTH_USER => null,
67
        self::PARAM_JAVA_AUTH_PASSWORD => null,
68
        self::PARAM_JAVA_DISABLE_AUTOLOAD => true,
69
        self::PARAM_JAVA_PREFER_VALUES => true,
70
        self::PARAM_JAVA_SEND_SIZE => 8192,
71
        self::PARAM_JAVA_RECV_SIZE => 8192,
72
        self::PARAM_JAVA_LOG_LEVEL => null,
73
        self::PARAM_JAVA_INTERNAL_ENCODING => 'UTF-8',
74
        self::PARAM_XML_PARSER_FORCE_SIMPLE_PARSER => false,
75
        self::PARAM_USE_PERSISTENT_CONNECTION => false
76
    ];
77
78
    /**
79
     * @var array
80
     */
81
    public $RUNTIME;
82
    public $result;
83
    public $exception;
84
    /**
85
     * @var ParserFactory
86
     */
87
    public $parser;
88
89
    /**
90
     * @var Arg|CompositeArg
91
     */
92
    public $simpleArg;
93
94
    /**
95
     * @var CompositeArg
96
     */
97
    public $compositeArg;
98
99
    /**
100
     * @var SimpleFactory
101
     */
102
    public $simpleFactory;
103
104
    /**
105
     * @var ProxyFactory
106
     */
107
    public $proxyFactory;
108
109
    /**
110
     * @var IteratorProxyFactory
111
     */
112
    public $iteratorProxyFactory;
113
114
    /**
115
     * @var ArrayProxyFactory
116
     */
117
    public $arrayProxyFactory;
118
119
    /**
120
     * @var ExceptionProxyFactory
121
     */
122
    public $exceptionProxyFactory;
123
124
    /**
125
     * @var ThrowExceptionProxyFactory
126
     */
127
    public $throwExceptionProxyFactory;
128
129
    /**
130
     * @var Arg|CompositeArg
131
     */
132
    public $arg;
133
    /**
134
     * @var int
135
     */
136
    public $asyncCtx;
137
138
    /**
139
     * @var int
140
     */
141
    public $cancelProxyCreationTag;
142
143
    /**
144
     * @var GlobalRef
145
     */
146
    public $globalRef;
147
    public $stack;
148
    /**
149
     * @var array
150
     */
151
    public $defaultCache = [];
152
    /**
153
     * @var array
154
     */
155
    public $asyncCache = [];
156
    /**
157
     * @var array
158
     */
159
    public $methodCache = [];
160
    public $isAsync = 0;
161
    /**
162
     * @var string|null
163
     */
164
    public $currentCacheKey;
165
166
    /**
167
     * @var string
168
     */
169
    public $currentArgumentsFormat;
170
    public $cachedJavaPrototype;
171
172
    /**
173
     * @var string|null
174
     */
175
    public $sendBuffer;
176
    /**
177
     * @var string|null
178
     */
179
    public $preparedToSendBuffer;
180
    public $inArgs;
181
182
    /**
183
     * @var int
184
     */
185
    protected $idx;
186
187
    /**
188
     * @var Protocol
189
     */
190
    public $protocol;
191
192
    /**
193
     * @var array
194
     */
195
    protected $cachedValues = [];
196
197
    /**
198
     * @var ArrayObject
199
     */
200
    protected $params;
201
202
    /**
203
     * @var string
204
     */
205
    public $java_servlet;
206
207
    /**
208
     * @var string
209
     */
210
    public $java_hosts;
211
212
    /**
213
     * @var int
214
     */
215
    public $java_recv_size;
216
217
    /**
218
     * @var int
219
     */
220
    public $java_send_size;
221
222
    /**
223
     * @var LoggerInterface
224
     */
225
    protected $logger;
226
227
    /**
228
     * @param ArrayObject $params
229
     */
230 30
    public function __construct(ArrayObject $params, LoggerInterface $logger)
231
    {
232 30
        $this->params = new ArrayObject(array_merge(self::DEFAULT_PARAMS, (array) $params));
233
234 30
        $this->logger = $logger;
235
236 30
        $this->java_send_size = $this->params[self::PARAM_JAVA_SEND_SIZE];
237 30
        $this->java_recv_size = $this->params[self::PARAM_JAVA_RECV_SIZE];
238
239 30
        $this->java_hosts = $this->params['JAVA_HOSTS'];
240 30
        $this->java_servlet = $this->params['JAVA_SERVLET'];
241
242 30
        $this->RUNTIME = [];
243 30
        $this->RUNTIME['NOTICE'] = '***USE echo $adapter->getDriver()->inspect(jVal) OR print_r($adapter->values(jVal)) TO SEE THE CONTENTS OF THIS JAVA OBJECT!***';
244 30
        $this->parser = new ParserFactory($this, $params['XML_PARSER_FORCE_SIMPLE_PARSER'] ?? false);
245 30
        $this->protocol = new Protocol($this, $this->java_hosts, $this->java_servlet, $this->java_recv_size, $this->java_send_size);
246 28
        $this->simpleFactory = new SimpleFactory($this);
247 28
        $this->proxyFactory = new ProxyFactory($this);
248 28
        $this->arrayProxyFactory = new ArrayProxyFactory($this);
249 28
        $this->iteratorProxyFactory = new IteratorProxyFactory($this);
250 28
        $this->exceptionProxyFactory = new ExceptionProxyFactory($this);
251 28
        $this->throwExceptionProxyFactory = new ThrowExceptionProxyFactory($this);
252 28
        $this->cachedJavaPrototype = new JavaProxyProxy($this);
253 28
        $this->simpleArg = new Arg($this);
254 28
        $this->globalRef = new GlobalRef();
255 28
        $this->asyncCtx = $this->cancelProxyCreationTag = 0;
256 28
        $this->methodCache = $this->defaultCache;
257 28
        $this->inArgs = false;
258
259 28
        $this->cachedValues = [
260
            'getContext' => null,
261
            'getServerName' => null
262
        ];
263 28
    }
264
265 3
    public function getLogger(): LoggerInterface
266
    {
267 3
        return $this->logger;
268
    }
269
270 114
    public function read($size): string
271
    {
272 114
        return $this->protocol->read($size);
273
    }
274
275 1
    public function setDefaultHandler(): void
276
    {
277 1
        $this->methodCache = $this->defaultCache;
278 1
    }
279
280 1
    public function setAsyncHandler(): void
281
    {
282 1
        $this->methodCache = $this->asyncCache;
283 1
    }
284
285
    /**
286
     * Handle request.
287
     *
288
     * @throws Exception\RuntimeException
289
     */
290 114
    public function handleRequests(): void
291
    {
292 114
        $tail_call = false;
293
        do {
294 114
            $this->arg = $this->simpleArg;
295 114
            $this->stack = [$this->arg];
296 114
            $this->idx = 0;
297 114
            $this->parser->parse();
298 113
            if (count($this->stack) > 1) {
299
                $arg = array_pop($this->stack);
300
                if ($arg instanceof ApplyArg) {
301
                    $this->apply($arg);
302
                } else {
303
                    $msg = 'Error: $arg should be of type ApplyArg, error in client';
304
                    $this->logger->critical($msg);
305
                    throw new Exception\RuntimeException($msg);
306
                }
307
                $tail_call = true;
308
            }
309 113
            $this->stack = null;
310 113
        } while ($tail_call);
311 113
    }
312
313
    /**
314
     * @param bool $wrap
315
     */
316 113
    public function getWrappedResult($wrap)
317
    {
318 113
        return $this->simpleArg->getResult($wrap);
319
    }
320
321 88
    public function getInternalResult(): JavaProxy
322
    {
323 88
        return $this->getWrappedResult(false);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getWrappedResult(false) returns the type Soluble\Japha\Bridge\Driver\Pjb62\JavaType which includes types incompatible with the type-hinted return Soluble\Japha\Bridge\Driver\Pjb62\JavaProxy.
Loading history...
324
    }
325
326 106
    public function getResult()
327
    {
328 106
        return $this->getWrappedResult(true);
329
    }
330
331
    /**
332
     * @param string $type
333
     *
334
     * @return SimpleFactory
335
     */
336 111
    protected function getProxyFactory(string $type): SimpleFactory
337
    {
338 111
        switch ($type[0]) {
339 111
            case 'E':
340 23
                $factory = $this->exceptionProxyFactory;
341 23
                break;
342 110
            case 'C':
343 5
                $factory = $this->iteratorProxyFactory;
344 5
                break;
345 109
            case 'A':
346 32
                $factory = $this->arrayProxyFactory;
347 32
                break;
348 104
            case 'O':
349
            default:
350 104
                $factory = $this->proxyFactory;
351
        }
352
353 111
        return $factory;
354
    }
355
356
    /**
357
     * @param Arg          $arg
358
     * @param CompositeArg $newArg
359
     */
360 15
    private function link(&$arg, &$newArg): void
361
    {
362 15
        $arg->linkResult($newArg->val);
363 15
        $newArg->parentArg = $arg;
364 15
    }
365
366
    /**
367
     * @param string $str
368
     *
369
     * @return int
370
     */
371 111
    protected function getExact($str)
372
    {
373 111
        return (int) hexdec($str);
374
    }
375
376
    /**
377
     * @param string $str
378
     *
379
     * @return mixed
380
     */
381 3
    private function getInexact($str)
382
    {
383 3
        $val = null;
384 3
        sscanf($str, '%e', $val);
385
386 3
        return $val;
387
    }
388
389
    /**
390
     * @param string $name
391
     * @param array  $st   param
392
     */
393 113
    public function begin(string $name, array $st): void
394
    {
395 113
        $arg = $this->arg;
396 113
        $code = $name[0];
397 113
        switch ($code) {
398 113
            case 'A':
399
                $object = $this->globalRef->get($this->getExact($st['v']));
400
                $newArg = new ApplyArg($this, 'A', $this->parser->getData($st['m']), $this->parser->getData($st['p']), $object, $this->getExact($st['n']));
401
                $this->link($arg, $newArg);
402
                array_push($this->stack, $this->arg = $newArg);
403
                break;
404 113
            case 'X':
405 15
                $newArg = new CompositeArg($this, $st['t']);
406 15
                $this->link($arg, $newArg);
407 15
                array_push($this->stack, $this->arg = $newArg);
408 15
                break;
409 113
            case 'P':
410 15
                if ($arg->type === 'H') {
411 10
                    $s = $st['t'];
412 10
                    if ($s[0] === 'N') {
413 6
                        $arg->setIndex($this->getExact($st['v']));
0 ignored issues
show
introduced by
The method setIndex() does not exist on Soluble\Japha\Bridge\Driver\Pjb62\Arg. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

413
                        $arg->/** @scrutinizer ignore-call */ 
414
                              setIndex($this->getExact($st['v']));
Loading history...
414
                    } else {
415 10
                        $arg->setIndex($this->parser->getData($st['v']));
416
                    }
417
                } else {
418 5
                    $arg->setNextIndex();
0 ignored issues
show
introduced by
The method setNextIndex() does not exist on Soluble\Japha\Bridge\Driver\Pjb62\Arg. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

418
                    $arg->/** @scrutinizer ignore-call */ 
419
                          setNextIndex();
Loading history...
419
                }
420 15
                break;
421 113
            case 'S':
422 88
                $arg->setResult($this->parser->getData($st['v']));
423 88
                break;
424 111
            case 'B':
425 16
                $s = $st['v'];
426 16
                $arg->setResult($s[0] === 'T');
427 16
                break;
428 111
            case 'L':
429 21
                $sign = $st['p'];
430 21
                $val = $this->getExact($st['v']);
431 21
                if ($sign[0] === 'A') {
432 1
                    $val *= -1;
433
                }
434 21
                $arg->setResult($val);
435 21
                break;
436 111
            case 'D':
437 3
                $arg->setResult($this->getInexact($st['v']));
438 3
                break;
439 111
            case 'V':
440 30
                if ($st['n'] !== 'T') {
441
                    $arg->setVoidSignature();
442
                }
443
                // possible bugfix, the break was missing here
444 30
                break;
445 111
            case 'N':
446 10
                $arg->setResult(null);
447 10
                break;
448 111
            case 'F':
449 8
                break;
450 111
            case 'O':
451 111
                $arg->setFactory($this->getProxyFactory($st['p']));
452 111
                $arg->setResult($this->asyncCtx = $this->getExact($st['v']));
453 111
                if ($st['n'] !== 'T') {
454
                    $arg->setSignature($st['m']);
455
                }
456 111
                break;
457 22
            case 'E':
458 22
                $arg->setFactory($this->throwExceptionProxyFactory);
459 22
                $arg->setException($st['m']);
460 22
                $arg->setResult($this->asyncCtx = $this->getExact($st['v']));
461 22
                break;
462
            default:
463
                $this->protocol->handler->shutdownBrokenConnection(
464
                    sprintf(
465
                        'Parser error, check the backend for details, "$name": %s, "$st": %s',
466
                        $name,
467
                        json_encode($st)
468
                    )
469
                );
470
        }
471 113
    }
472
473
    /**
474
     * @param string $name
475
     */
476 112
    public function end(string $name): void
477
    {
478 112
        switch ($name[0]) {
479 112
            case 'X':
480 15
                $frame = array_pop($this->stack);
481 15
                $this->arg = $frame->parentArg;
482 15
                break;
483
        }
484 112
    }
485
486
    /**
487
     * @throws JavaException
488
     *
489
     * @param mixed $arg
490
     */
491 110
    protected function writeArg($arg): void
492
    {
493 110
        if (is_string($arg)) {
494 85
            $this->protocol->writeString($arg);
495 102
        } elseif (is_object($arg)) {
496 98
            if (!$arg instanceof JavaType) {
497 1
                $msg = "Client failed to writeArg(), IllegalArgument 'arg:".get_class($arg)."' not a Java object, using NULL instead";
498 1
                $this->logger->error("[soluble-japha] $msg (".__METHOD__.')');
499
                //trigger_error($msg, E_USER_WARNING);
500 1
                $this->protocol->writeObject(null);
501
            } else {
502 98
                $this->protocol->writeObject($arg->get__java());
503
            }
504 33
        } elseif (null === $arg) {
505 2
            $this->protocol->writeObject(null);
506 32
        } elseif (is_bool($arg)) {
507 3
            $this->protocol->writeBoolean($arg);
508 32
        } elseif (is_int($arg)) {
509 25
            $this->protocol->writeLong($arg);
510 18
        } elseif (is_float($arg)) {
511 4
            $this->protocol->writeDouble($arg);
512 15
        } elseif (is_array($arg)) {
513 14
            $wrote_begin = false;
514 14
            foreach ($arg as $key => $val) {
515 13
                if (is_string($key)) {
516 10
                    if (!$wrote_begin) {
517 10
                        $wrote_begin = true;
518 10
                        $this->protocol->writeCompositeBegin_h();
519
                    }
520 10
                    $this->protocol->writePairBegin_s($key);
521 10
                    $this->writeArg($val);
522 10
                    $this->protocol->writePairEnd();
523
                } else {
524 7
                    if (!$wrote_begin) {
525 7
                        $wrote_begin = true;
526 7
                        $this->protocol->writeCompositeBegin_h();
527
                    }
528 7
                    $this->protocol->writePairBegin_n($key);
529 7
                    $this->writeArg($val);
530 7
                    $this->protocol->writePairEnd();
531
                }
532
            }
533 14
            if (!$wrote_begin) {
534 1
                $this->protocol->writeCompositeBegin_a();
535
            }
536 14
            $this->protocol->writeCompositeEnd();
537
        }
538 110
    }
539
540
    /**
541
     * @param array $args
542
     */
543 114
    protected function writeArgs(array $args): void
544
    {
545 114
        $this->inArgs = true;
546 114
        foreach ($args as $arg) {
547 110
            $this->writeArg($arg);
548
        }
549 114
        $this->inArgs = false;
550 114
    }
551
552
    /**
553
     * @param string $name java class name, i.e java.math.BigInteger
554
     * @param array  $args
555
     *
556
     * @return JavaProxy
557
     */
558 72
    public function createObject(string $name, array $args): JavaProxy
559
    {
560 72
        $this->protocol->createObjectBegin($name);
561 72
        $this->writeArgs($args);
562 72
        $this->protocol->createObjectEnd();
563
564 71
        return $this->getInternalResult();
565
    }
566
567
    /**
568
     * @param string $name java class name, i.e java.math.BigInteger
569
     * @param array  $args
570
     *
571
     * @return JavaProxy
572
     */
573 24
    public function referenceObject(string $name, array $args): JavaProxy
574
    {
575 24
        $this->protocol->referenceBegin($name);
576 24
        $this->writeArgs($args);
577 24
        $this->protocol->referenceEnd();
578 24
        $val = $this->getInternalResult();
579
580 19
        return $val;
581
    }
582
583
    /**
584
     * @param int    $object
585
     * @param string $property
586
     *
587
     * @return mixed
588
     */
589 24
    public function getProperty(int $object, string $property)
590
    {
591 24
        $this->protocol->propertyAccessBegin($object, $property);
592 24
        $this->protocol->propertyAccessEnd();
593
594 24
        return $this->getResult();
595
    }
596
597
    /**
598
     * @param int    $object
599
     * @param string $property
600
     * @param mixed  $arg
601
     */
602 2
    public function setProperty(int $object, string $property, $arg): void
603
    {
604 2
        $this->protocol->propertyAccessBegin($object, $property);
605 2
        $this->writeArg($arg);
606 2
        $this->protocol->propertyAccessEnd();
607 2
        $this->getResult();
608
    }
609
610
    /**
611
     * Invoke a method on java object.
612
     *
613
     * @param int    $object_id a java object or type
614
     * @param string $method    method name
615
     * @param array  $args      arguments to send with method
616
     *
617
     * @return mixed
618
     */
619 106
    public function invokeMethod(int $object_id, string $method, array $args = [])
620
    {
621 106
        $this->protocol->invokeBegin($object_id, $method);
622 106
        $this->writeArgs($args);
623
624 106
        $this->protocol->invokeEnd();
625 106
        $val = $this->getResult();
626
627 106
        return $val;
628
    }
629
630
    /**
631
     * Write exit code.
632
     *
633
     * @param int $code
634
     */
635
    public function setExitCode(int $code): void
636
    {
637
        if (isset($this->protocol)) {
638
            $this->protocol->writeExitCode($code);
639
        }
640
    }
641
642
    /**
643
     * Unref will be called whenever a JavaObject is not used,
644
     * see JavaProxy::__destruct() method.
645
     *
646
     * @param int $object object identifier
647
     */
648 107
    public function unref(?int $object): void
649
    {
650 107
        if (isset($this->protocol)) {
651 107
            $this->protocol->writeUnref($object);
652
        }
653 107
    }
654
655
    /**
656
     * @param ApplyArg $arg
657
     *
658
     * @throws Exception\JavaException
659
     * @throws Exception\RuntimeException
660
     */
661
    public function apply(ApplyArg $arg): void
662
    {
663
        $name = $arg->p;
664
        $object = $arg->v;
665
        $ob = ($object == null) ? $name : [&$object, $name];
666
        $isAsync = $this->isAsync;
667
        $methodCache = $this->methodCache;
668
        $currentArgumentsFormat = $this->currentArgumentsFormat;
669
        try {
670
            $res = $arg->getResult(true);
671
            if ((($object == null) && !function_exists($name)) || (!($object == null) && !method_exists($object, $name))) {
672
                throw new Exception\JavaException('java.lang.NoSuchMethodError', (string) $name);
673
            }
674
            $res = call_user_func($ob, $res);
675
            if (is_object($res) && (!($res instanceof JavaType))) {
676
                $msg = "Client failed to applyArg(), Object returned from '$name()' is not a Java object";
677
                $this->logger->warning("[soluble-japha] $msg (".__METHOD__.')');
678
                trigger_error($msg, E_USER_WARNING);
679
680
                $this->protocol->invokeBegin(0, 'makeClosure');
681
                $this->protocol->writeULong($this->globalRef->add($res));
682
                $this->protocol->invokeEnd();
683
                $res = $this->getResult();
684
            }
685
            $this->protocol->resultBegin();
686
            $this->writeArg($res);
687
            $this->protocol->resultEnd();
688
        } catch (Exception\JavaException $e) {
689
            $trace = $e->getTraceAsString();
690
            $this->protocol->resultBegin();
691
            $this->protocol->writeException($e->__java, $trace);
692
            $this->protocol->resultEnd();
693
        } catch (\Throwable $ex) {
694
            $msg = 'Unchecked exception detected in callback ('.$ex->__toString().')';
695
            $this->logger->error("[soluble-japha] $msg (".__METHOD__.')');
696
            trigger_error($msg, E_USER_WARNING);
697
            throw new Exception\RuntimeException($msg);
698
        }
699
        $this->isAsync = $isAsync;
700
        $this->methodCache = $methodCache;
701
        $this->currentArgumentsFormat = $currentArgumentsFormat;
702
    }
703
704
    /**
705
     * Cast an object to a certain type.
706
     *
707
     * @param JavaProxy $object
708
     * @param string    $type
709
     *
710
     * @return mixed
711
     *
712
     * @throws Exception\RuntimeException
713
     */
714 8
    public function cast(JavaProxy $object, $type)
715
    {
716 8
        $code = strtoupper($type[0]);
717 8
        switch ($code) {
718 8
            case 'S':
719
                return $this->invokeMethod(0, 'castToString', [$object]);
720 8
            case 'B':
721
                return $this->invokeMethod(0, 'castToBoolean', [$object]);
722 8
            case 'L':
723 8
            case 'I':
724
                return $this->invokeMethod(0, 'castToExact', [$object]);
725 8
            case 'D':
726 8
            case 'F':
727
                return $this->invokeMethod(0, 'castToInExact', [$object]);
728 8
            case 'N':
729
                return null;
730 8
            case 'A':
731 8
                return $this->invokeMethod(0, 'castToArray', [$object]);
732
            case 'O':
733
                return $object;
734
            default:
735
                throw new Exception\RuntimeException("Illegal type '$code' for casting");
736
        }
737
    }
738
739
    /**
740
     * Returns the jsr223 script context handle.
741
     *
742
     * Exposes the bindings from the ENGINE_SCOPE to PHP scripts. Values
743
     * set with engine.set("key", val) can be fetched from PHP with
744
     * java_context()->get("key"). Values set with
745
     * java_context()->put("key", java_closure($val)) can be fetched from
746
     * Java with engine.get("key"). The get/put methods are convenience shortcuts for getAttribute/setAttribute. Example:
747
     * <code>
748
     * engine.put("key1", 2);
749
     * engine.eval("<?php java_context()->put("key2", 1+(int)(string)java_context()->get('key1'));?>");
750
     * System.out.println(engine.get("key2"));
751
     *</code>
752
     *
753
     * A synchronized init() procedure can be called from the context to initialize a library once, and a shutdown hook can be registered to destroy the library before the (web-) context is destroyed. The init hook can be written in PHP, but the shutdown hook must be written in Java. Example:
754
     * <code>
755
     * function getShutdownHook() { return java("myJavaHelper")->getShutdownHook(); }
756
     * function call() { // called by init()
757
     *   ...
758
     *   // register shutdown hook
759
     *   java_context()->onShutdown(getShutdownHook());
760
     * }
761
     * java_context()->init(java_closure(null, null, java("java.util.concurrent.Callable")));
762
     * </code>
763
     *
764
     * It is possible to access implicit web objects (the session, the
765
     * application store etc.) from the context. Example:
766
     * <code>
767
     * $req = $ctx->getHttpServletRequest();
768
     * $res = $ctx->getHttpServletResponse();
769
     * $servlet = $ctx->getServlet();
770
     * $config = $ctx->getServletConfig();
771
     * $context = $ctx->getServletContext();
772
     * </code>
773
     *
774
     * The global bindings (shared with all available script engines) are
775
     * available from the GLOBAL_SCOPE, the script engine bindings are
776
     * available from the ENGINE_SCOPE. Example
777
     *
778
     * <code>
779
     * define ("ENGINE_SCOPE", 100);
780
     * define ("GLOBAL_SCOPE", 200);
781
     * echo java_context()->getBindings(ENGINE_SCOPE)->keySet();
782
     * echo java_context()->getBindings(GLOBAL_SCOPE)->keySet();
783
     * </code>
784
     *
785
     * Furthermore the context exposes the java continuation to PHP scripts.
786
     * Example which closes over the current environment and passes it back to java:
787
     * <code>
788
     * define ("ENGINE_SCOPE", 100);
789
     * $ctx = java_context();
790
     * if(java_is_false($ctx->call(java_closure()))) die "Script should be called from java";
791
     * </code>
792
     *
793
     * A second example which shows how to invoke PHP methods without the JSR 223 getInterface() and invokeMethod()
794
     * helper procedures. The Java code can fetch the current PHP continuation from the context using the key "php.java.bridge.PhpProcedure":
795
     * <code>
796
     * String s = "<?php class Runnable { function run() {...} };
797
     *            // example which captures an environment and
798
     *            // passes it as a continuation back to Java
799
     *            $Runnable = java('java.lang.Runnable');
800
     *            java_context()->call(java_closure(new Runnable(), null, $Runnable));
801
     *            ?>";
802
     * ScriptEngine e = new ScriptEngineManager().getEngineByName("php-invocable");
803
     * e.eval (s);
804
     * Thread t = new Thread((Runnable)e.get("php.java.bridge.PhpProcedure"));
805
     * t.join ();
806
     * ((Closeable)e).close ();
807
     * </code>
808
     *
809
     * @return Interfaces\JavaObject
810
     */
811 4
    public function getContext(): Interfaces\JavaObject
812
    {
813 4
        if ($this->cachedValues['getContext'] === null) {
814 1
            $this->cachedValues['getContext'] = $this->invokeMethod(0, 'getContext', []);
815
        }
816
817 4
        return $this->cachedValues['getContext'];
818
    }
819
820
    /**
821
     * Return a java (servlet) session handle.
822
     *
823
     * When getJavaSession() is called without
824
     * arguments, the session is shared with java.
825
     * Example:
826
     * <code>
827
     * $driver->getJavaSession()->put("key", new Java("java.lang.Object"));
828
     * [...]
829
     * </code>
830
     * The java components (jsp, servlets) can retrieve the value, for
831
     * example with:
832
     * <code>
833
     * getSession().getAttribute("key");
834
     * </code>
835
     *
836
     * When java_session() is called with a session name, the session
837
     * is not shared with java and no cookies are set. Example:
838
     * <code>
839
     * $driver->getJavaSession("myPublicApplicationStore")->put("key", "value");
840
     * </code>
841
     *
842
     * When java_session() is called with a second argument set to true,
843
     * a new session is allocated, the old session is destroyed if necessary.
844
     * Example:
845
     * <code>
846
     * $driver->getJavaSession(null, true)->put("key", "val");
847
     * </code>
848
     *
849
     * The optional third argument specifies the default lifetime of the session, it defaults to <code> session.gc_maxlifetime </code>. The value 0 means that the session never times out.
850
     *
851
     * The synchronized init() and onShutdown() callbacks from
852
     * java_context() and the JPersistenceAdapter (see
853
     * JPersistenceAdapter.php from the php_java_lib directory) may also
854
     * be useful to load a Java singleton object after the JavaBridge
855
     * library has been initialized, and to store it right before the web
856
     * context or the entire JVM will be terminated.
857
     *
858
     * @param array $args
859
     *
860
     * @return Interfaces\JavaObject
861
     */
862
    public function getSession(array $args = []): Interfaces\JavaObject
863
    {
864
        if (!isset($args[0])) {
865
            $args[0] = null;
866
        }
867
868
        if (!isset($args[1])) {
869
            $args[1] = 0;
870
        } // ISession.SESSION_GET_OR_CREATE
871
        elseif ($args[1] === true) {
872
            $args[1] = 1;
873
        } // ISession.SESSION_CREATE_NEW
874
        else {
875
            $args[1] = 2;
876
        } // ISession.SESSION_GET
877
878
        if (!isset($args[2])) {
879
            $args[2] = HelperFunctions::java_get_session_lifetime();
880
        }
881
882
        return $this->invokeMethod(0, 'getSession', $args);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->invokeMeth...0, 'getSession', $args) returns the type Soluble\Japha\Bridge\Driver\Pjb62\JavaType which is incompatible with the type-hinted return Soluble\Japha\Interfaces\JavaObject.
Loading history...
883
    }
884
885
    /**
886
     * @return string
887
     */
888 1
    public function getServerName(): string
889
    {
890 1
        if ($this->cachedValues['getServerName'] === null) {
891 1
            $this->cachedValues['getServerName'] = $this->protocol->getServerName();
892
        }
893
894 1
        return $this->cachedValues['getServerName'];
895
    }
896
897
    /**
898
     * Return client parameters.
899
     *
900
     * @return ArrayObject
901
     */
902
    public function getParams(): \ArrayObject
903
    {
904
        return $this->params;
905
    }
906
907
    /**
908
     * Return client parameter by name.
909
     *
910
     * @param string $param
911
     *
912
     * @return mixed
913
     */
914 97
    public function getParam($param)
915
    {
916 97
        return $this->params[$param];
917
    }
918
}
919