Completed
Push — master ( 3ba1a9...d49138 )
by Sébastien
04:32
created

Pjb62Driver::inspect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.5

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 3
cts 6
cp 0.5
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
crap 2.5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\Japha\Bridge\Driver\Pjb62;
6
7
use Psr\Log\LoggerInterface;
8
use Psr\Log\NullLogger;
9
use Soluble\Japha\Bridge\Driver\AbstractDriver;
10
use Soluble\Japha\Bridge\Driver\ClientInterface;
11
use Soluble\Japha\Bridge\Driver\Pjb62\Exception\BrokenConnectionException as Pjb62BrokenConnectionException;
12
use Soluble\Japha\Bridge\Exception\BrokenConnectionException;
13
use Soluble\Japha\Interfaces;
14
use Soluble\Japha\Bridge\Exception;
15
16
class Pjb62Driver extends AbstractDriver
17
{
18
    /**
19
     * @var bool
20
     */
21
    protected $connected = false;
22
23
    /**
24
     * @var PjbProxyClient
25
     */
26
    protected $pjbProxyClient;
27
28
    /**
29
     * @var LoggerInterface
30
     */
31
    protected $logger;
32
33
    /**
34
     * Constructor.
35
     *
36
     * <code>
37
     *
38
     * $ba = new Pjb62Driver([
39
     *     'servlet_address' => 'http://127.0.0.1:8080/javabridge-bundle/servlet.phpjavabridge'
40
     *      //'java_default_timezone' => null,
41
     *      //'java_prefer_values' => true,
42
     *      //'java_log_level' => null,
43
     *      //'java_send_size' => 8192,
44
     *      //'java_recv_size' => 8192,
45
     *      //'internal_encoding' => 'UTF-8',
46
     *      //'force_simple_xml_parser' => false
47
     *    ], $logger);
48
     *
49
     * </code>
50
     *
51
     * @param array           $options
52
     * @param LoggerInterface $logger
53
     *
54
     * @throws Exception\InvalidArgumentException
55
     * @throws Exception\ConnectionException
56
     */
57 139
    public function __construct(array $options, LoggerInterface $logger = null)
58
    {
59 139
        if ($logger === null) {
60 1
            $logger = new NullLogger();
61
        }
62
63 139
        $this->logger = $logger;
0 ignored issues
show
Documentation Bug introduced by
It seems like $logger can also be of type object<Psr\Log\NullLogger>. However, the property $logger is declared as type object<Psr\Log\LoggerInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
64
65
        try {
66 139
            $this->pjbProxyClient = PjbProxyClient::getInstance($options, $this->logger);
67 4
        } catch (Exception\ConnectionException $e) {
68 2
            $address = $options['servlet_address'];
69 2
            $msg = "Cannot connect to php-java-bridge server on '$address', server didn't respond.";
70 2
            $this->logger->critical("[soluble-japha] $msg (" . $e->getMessage() . ')');
71 2
            throw $e;
72 2
        } catch (Exception\InvalidArgumentException $e) {
73 2
            $msg = 'Invalid arguments, cannot initiate connection to java-bridge.';
74 2
            $this->logger->error("[soluble-japha] $msg (" . $e->getMessage() . ')');
75 2
            throw $e;
76
        }
77 136
    }
78
79 1
    public function getLogger(): LoggerInterface
80
    {
81 1
        return $this->logger;
82
    }
83
84
    /**
85
     * Return underlying bridge client.
86
     *
87
     * @return PjbProxyClient
88
     */
89 9
    public function getClient(): ClientInterface
90
    {
91 9
        return $this->pjbProxyClient;
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     *
97
     * @throws BrokenConnectionException
98
     */
99 50
    public function getJavaClass(string $class_name): Interfaces\JavaClass
100
    {
101
        try {
102 50
            $class = $this->pjbProxyClient->getJavaClass($class_name);
103 3
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
104 1
            PjbProxyClient::unregisterInstance();
105 1
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
106
        }
107
108 47
        return $class;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     *
114
     * @throws BrokenConnectionException
115
     */
116 65
    public function instanciate(string $class_name, ...$args): Interfaces\JavaObject
117
    {
118
        try {
119 65
            $java = new Java($class_name, ...$args);
120 4
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
121 2
            PjbProxyClient::unregisterInstance();
122 2
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
123
        }
124
125 62
        return $java;
126
    }
127
128
    /**
129
     * Set the java file encoding, for example UTF-8, ISO-8859-1 or ASCII.
130
     *
131
     * Needed because php does not support unicode. All string to byte array
132
     * conversions use this encoding. Example:
133
     *
134
     * @param string $encoding Please see Java file.encoding documentation for a list of valid encodings.
135
     *
136
     * @throws BrokenConnectionException
137
     */
138 1
    public function setFileEncoding(string $encoding): void
139
    {
140 1
        $this->invoke(null, 'setFileEncoding', [$encoding]);
141 1
    }
142
143
    /**
144
     * Return bridge connection options.
145
     *
146
     * @throws BrokenConnectionException
147
     *
148
     * @return Interfaces\JavaObject Java("io.soluble.pjb.bridge.Options")
149
     */
150 1
    public function getConnectionOptions(): Interfaces\JavaObject
151
    {
152 1
        return $this->invoke(null, 'getOptions');
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     *
158
     * @throws BrokenConnectionException
159
     */
160 4
    public function invoke(Interfaces\JavaType $javaObject = null, string $method, array $args = [])
161
    {
162
        try {
163 4
            return $this->pjbProxyClient->invokeMethod($javaObject, $method, $args);
164 1
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
165
            PjbProxyClient::unregisterInstance();
166
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
167
        }
168
    }
169
170
    /**
171
     * Returns the jsr223 script context handle.
172
     *
173
     * @throws BrokenConnectionException
174
     *
175
     * @return Interfaces\JavaObject
176
     */
177 5
    public function getContext(): Interfaces\JavaObject
178
    {
179
        try {
180 5
            return $this->pjbProxyClient::getClient()->getContext();
181 1
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
182
            PjbProxyClient::unregisterInstance();
183
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
184
        }
185
    }
186
187
    /**
188
     * Return java servlet session.
189
     *
190
     * <code>
191
     * $session = $adapter->getDriver()->getJavaSession();
192
     * $counter = $session->get('counter');
193
     * if ($adapter->isNull($counter)) {
194
     *    $session->put('counter', 1);
195
     * } else {
196
     *    $session->put('counter', $counter + 1);
197
     * }
198
     * </code>
199
     *
200
     * @param array $args
201
     *
202
     * @throws BrokenConnectionException
203
     *
204
     * @return Interfaces\JavaObject
205
     */
206 2
    public function getJavaSession(array $args = []): Interfaces\JavaObject
207
    {
208
        try {
209 2
            return $this->pjbProxyClient::getClient()->getSession();
210 2
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
211
            PjbProxyClient::unregisterInstance();
212
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
213
        }
214
    }
215
216
    /**
217
     * Inspect the class internals.
218
     *
219
     * @param Interfaces\JavaObject $javaObject
220
     *
221
     * @throws BrokenConnectionException
222
     *
223
     * @return string
224
     */
225 12
    public function inspect(Interfaces\JavaObject $javaObject): string
226
    {
227
        try {
228 12
            $inspect = $this->pjbProxyClient->inspect($javaObject);
229
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
230
            PjbProxyClient::unregisterInstance();
231
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
232
        }
233
234 12
        return $inspect;
235
    }
236
237
    /**
238
     * {@inheritdoc}
239
     *
240
     * @throws BrokenConnectionException
241
     */
242 8
    public function isInstanceOf(Interfaces\JavaObject $javaObject, $className): bool
243
    {
244
        try {
245 8
            return $this->pjbProxyClient->isInstanceOf($javaObject, $className);
246 4
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
247
            PjbProxyClient::unregisterInstance();
248
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
249
        }
250
    }
251
252
    /**
253
     * {@inheritdoc}
254
     *
255
     * @throws BrokenConnectionException
256
     */
257 12
    public function values(Interfaces\JavaObject $javaObject)
258
    {
259
        try {
260 12
            return $this->pjbProxyClient->getValues($javaObject);
261
        } catch (Pjb62BrokenConnectionException|Exception\InvalidUsageException $e) {
262
            PjbProxyClient::unregisterInstance();
263
            throw new BrokenConnectionException($e->getMessage(), $e->getCode(), $e);
264
        }
265
    }
266
267
    /**
268
     * Return java bridge header or empty string if nothing.
269
     *
270
     * @param string $name
271
     * @param array  $array
272
     *
273
     * @return string header value or empty string if not exists
274
     */
275 28
    public static function getJavaBridgeHeader(string $name, array $array): string
276
    {
277 28
        if (array_key_exists($name, $array)) {
278 1
            return $array[$name];
279
        }
280 28
        $name = "HTTP_$name";
281 28
        if (array_key_exists($name, $array)) {
282 1
            return $array[$name];
283
        }
284
285 28
        return '';
286
    }
287
288
    /**
289
     * Cast internal objects to a new type.
290
     *
291
     * @param Interfaces\JavaObject|JavaType $javaObject
292
     * @param string                         $cast_type
293
     *
294
     * @return mixed
295
     */
296 8
    public static function castPjbInternal($javaObject, string $cast_type)
297
    {
298 8
        if (!$javaObject instanceof JavaType) {
299
            $first_char = strtoupper($cast_type[0]);
300
            switch ($first_char) {
301
                case 'S':
302
                    return (string) $javaObject;
303
                case 'B':
304
                    return (bool) $javaObject;
305
                case 'L':
306
                case 'I':
307
                    return (int) $javaObject;
308
                case 'D':
309
                case 'F':
310
                    return (float) $javaObject;
311
                case 'N':
312
                    return null;
313
                case 'A':
314
                    return (array) $javaObject;
315
                case 'O':
316
                    return (object) $javaObject;
317
            }
318
        }
319
320 8
        return $javaObject->__cast($cast_type);
0 ignored issues
show
Bug introduced by
The method __cast does only exist in Soluble\Japha\Bridge\Driver\Pjb62\JavaType, but not in Soluble\Japha\Interfaces\JavaObject.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
321
    }
322
323
    /**
324
     * {@inheritdoc}
325
     */
326
    public function cast(Interfaces\JavaObject $javaObject, string $cast_type)
327
    {
328
        /* @todo see how can it be possible to clean up to new structure
329
            const CAST_TYPE_STRING  = 'string';
330
            const CAST_TYPE_BOOLEAN = 'boolean';
331
            const CAST_TYPE_INTEGER = 'integer';
332
            const CAST_TYPE_FLOAT   = 'float';
333
            const CAST_TYPE_ARRAY   = 'array';
334
            const CAST_TYPE_NULL    = 'null';
335
            const CAST_TYPE_OBJECT  = 'object';
336
            const CAST_TYPE_NULL -> null
337
         */
338
        $first_char = strtoupper(substr($cast_type, 0, 1));
339
        switch ($first_char) {
340
            case 'S':
341
                return (string) $javaObject;
342
            case 'B':
343
                return (bool) $javaObject;
344
            case 'L':
345
            case 'I':
346
                return (int) $javaObject;
347
            case 'D':
348
            case 'F':
349
                return (float) $javaObject;
350
            case 'N':
351
                return null;
352
            case 'A':
353
                return (array) $javaObject;
354
            case 'O':
355
                return (object) $javaObject;
356
            default:
357
                throw new Exception\RuntimeException("Unsupported cast_type parameter: $cast_type");
358
        }
359
    }
360
361
    /**
362
     * Return object java class name.
363
     *
364
     * @throws Exception\UnexpectedException
365
     * @throws BrokenConnectionException
366
     *
367
     * @param Interfaces\JavaObject $javaObject
368
     *
369
     * @return string
370
     */
371 11
    public function getClassName(Interfaces\JavaObject $javaObject): string
372
    {
373 11
        $inspect = $this->inspect($javaObject);
374
375
        // [class java.sql.DriverManager:
376 11
        $matches = [];
377 11
        preg_match('/^\[class (.+)\:/', $inspect, $matches);
378 11
        if (!isset($matches[1]) || $matches[1] == '') {
379
            throw new Exception\UnexpectedException(__METHOD__ . ' Cannot determine class name');
380
        }
381
382 11
        return $matches[1];
383
    }
384
}
385