ProtocolHandler::handleError()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 2
eloc 5
nc 2
nop 2
1
<?php
2
3
/**
4
 * \AppserverIo\Stomp\ProtocolHandler
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Lars Roettig <[email protected]>
15
 * @copyright 2016 TechDivision GmbH - <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      http://www.appserver.io/
18
 */
19
20
21
namespace AppserverIo\Stomp;
22
23
use AppserverIo\Messaging\MessageQueue;
24
use AppserverIo\Messaging\QueueConnectionFactory;
25
use AppserverIo\Messaging\StringMessage;
26
use AppserverIo\Stomp\Interfaces\AuthenticatorInterface;
27
use AppserverIo\Stomp\Authenticator\SimpleAuthenticator;
28
use AppserverIo\Stomp\Exception\ProtocolException;
29
use AppserverIo\Stomp\Interfaces\ProtocolHandlerInterface;
30
use AppserverIo\Stomp\Protocol\ClientCommands;
31
use AppserverIo\Stomp\Protocol\CommonValues;
32
use AppserverIo\Stomp\Protocol\Headers;
33
use AppserverIo\Stomp\Protocol\ServerCommands;
34
use AppserverIo\Stomp\Utils\ErrorMessages;
35
36
/**
37
 * Implementation to handle stomp request.
38
 *
39
 * @author    Lars Roettig <[email protected]>
40
 * @copyright 2016 TechDivision GmbH - <[email protected]>
41
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
42
 * @link      http://www.appserver.io/
43
 * @link      https://github.com/stomp/stomp-spec/blob/master/src/stomp-specification-1.1.md
44
 */
45
class ProtocolHandler implements ProtocolHandlerInterface
46
{
47
48
    /**
49
     * Holds the Separator for protocol versions.
50
     *
51
     * @var string
52
     */
53
    const SEPARATOR = ",";
54
55
    /**
56
     * The supported protocol versions.
57
     *
58
     * @var array
59
     */
60
    protected $supportedProtocolVersions;
61
62
    /**
63
     * Holds the stomp authenticator.
64
     *
65
     * @var \AppserverIo\Stomp\Interfaces\AuthenticatorInterface
66
     */
67
    protected $authenticator;
68
69
    /**
70
     * Holds the response as stomp frame.
71
     *
72
     * @var \AppserverIo\Stomp\Frame
73
     */
74
    protected $response;
75
76
    /**
77
     * Holds the state to close parent connection.
78
     *
79
     * @var bool
80
     */
81
    protected $mustConnectionClose;
82
83
    /**
84
     * Holds the queue session.
85
     *
86
     * @var \AppserverIo\Messaging\QueueSession
87
     */
88
    protected $session;
89
90
    /**
91
     * Init new stomp protocol handler.
92
     */
93
    public function __construct()
94
    {
95
        // set the supported protocol versions to 1.0,1.1,1.2
96
        $this->injectSupportedProtocolVersions(array(
97
            CommonValues::V1_0 => "",
98
            CommonValues::V1_1 => "",
99
            CommonValues::V1_2 => ""
100
        ));
101
        $this->init();
102
    }
103
104
    /**
105
     * Init the StompProtocolHandler
106
     *
107
     * @return void
108
     */
109
    public function init()
110
    {
111
        $this->injectAuthenticator(new SimpleAuthenticator());
112
        $this->mustConnectionClose = false;
113
    }
114
115
    /**
116
     * Injects the supported protocol versions for the handler.
117
     *
118
     * @param array $supportedProtocolVersion Array with supported protocol versions
119
     *
120
     * @return void
121
     */
122
    public function injectSupportedProtocolVersions(array $supportedProtocolVersion)
123
    {
124
        $this->supportedProtocolVersions = $supportedProtocolVersion;
125
    }
126
127
    /**
128
     * Injects the authenticator for the handler.
129
     *
130
     * @param \AppserverIo\Stomp\Interfaces\AuthenticatorInterface $authenticator The $authenticator
131
     *
132
     * @return void
133
     */
134
    public function injectAuthenticator(AuthenticatorInterface $authenticator)
135
    {
136
        $this->authenticator = $authenticator;
137
    }
138
139
    /**
140
     * Returns must the parent handler the connection close
141
     *
142
     * @return bool
143
     */
144
    public function getMustConnectionClose()
145
    {
146
        return $this->mustConnectionClose;
147
    }
148
149
    /**
150
     * Handle the connect request.
151
     *
152
     * @param \AppserverIo\Stomp\Frame $stompFrame The Stomp frame to handle the connect.
153
     *
154
     * @return void
155
     *
156
     * throws \AppserverIo\Stomp\Exception\ProtocolException
157
     */
158
    public function handle(Frame $stompFrame)
159
    {
160
        switch ($stompFrame->getCommand()) {
161
            case ClientCommands::CONNECT:
162
            case ClientCommands::STOMP: // case for client connect
163
                $this->response = $this->handleConnect($stompFrame);
164
                break;
165
166
            case ClientCommands::SEND: // case for client send message
167
                $this->handleSend($stompFrame);
168
                $this->response = null;
169
                break;
170
171
            case ClientCommands::DISCONNECT: // case for client disconnect
172
                $this->response = $this->handleDisConnect($stompFrame);
173
                break;
174
        }
175
    }
176
177
    /**
178
     * Detects the protocol version by given string
179
     *
180
     * @param string $protocolVersion The version string to detect the version
181
     *
182
     * @return string
183
     *
184
     * @throws \AppserverIo\Stomp\Exception\ProtocolException
185
     */
186
    public function detectProtocolVersion($protocolVersion)
187
    {
188
        // is not required to detect the version
189
        if (strpos($protocolVersion, ProtocolHandler::SEPARATOR) === false) {
190
            return $protocolVersion;
191
        }
192
193
        $supportedProtocolVersions = array_keys($this->supportedProtocolVersions);
194
        $acceptsVersions = explode(ProtocolHandler::SEPARATOR, $protocolVersion);
195
        $acceptsVersions = array_intersect($acceptsVersions, $supportedProtocolVersions);
196
197
        if (count($acceptsVersions) == 0) {
198
            $supportedVersions = implode(" ", array_keys($this->supportedProtocolVersions));
199
            throw new ProtocolException(sprintf(ErrorMessages::SUPPORTED_PROTOCOL_VERSIONS, $supportedVersions));
200
        }
201
202
        return max($acceptsVersions);
203
    }
204
205
    /**
206
     * Handle the connect request.
207
     *
208
     * @param \AppserverIo\Stomp\Frame $stompFrame The Stomp frame to handle the connect.
209
     *
210
     * @return \AppserverIo\Stomp\Frame The stomp frame Response
211
     *
212
     * @throws \AppserverIo\Stomp\Exception\ProtocolException
213
     */
214
    protected function handleConnect(Frame $stompFrame)
215
    {
216
        $protocolVersion = $stompFrame->getHeaderValueByKey(Headers::ACCEPT_VERSION);
217
218
        // detects the protocol version by given string
219
        $protocolVersion = $this->detectProtocolVersion($protocolVersion);
220
221
        $login = $stompFrame->getHeaderValueByKey(Headers::LOGIN);
222
        $passCode = $stompFrame->getHeaderValueByKey(Headers::PASSCODE);
223
224
        $this->getAuthenticator()->connect($login, $passCode);
225
226
        // create new session
227
        $connection = QueueConnectionFactory::createQueueConnection("stomp");
228
        $this->setSession($connection->createQueueSession());
229
230
        // create new stomp CONNECTED frame with headers and return
231
        $headers = array(
232
            Headers::SESSION => $this->getSession()->getId(),
233
            Headers::VERSION => $protocolVersion,
234
            Headers::SERVER => CommonValues::SERVER_NAME,
235
            Headers::HEART_BEAT => CommonValues::DEFAULT_HEART_BEAT
236
        );
237
238
        // returns the response frame
239
        return new Frame(ServerCommands::CONNECTED, $headers);
240
    }
241
242
    /**
243
     * Returns the authenticator,
244
     *
245
     * @return \AppserverIo\Stomp\Interfaces\AuthenticatorInterface
246
     */
247
    public function getAuthenticator()
248
    {
249
        return $this->authenticator;
250
    }
251
252
    /**
253
     * Returns the message queue session.
254
     *
255
     * @return \AppserverIo\Messaging\QueueSession
256
     */
257
    public function getSession()
258
    {
259
        return $this->session;
260
    }
261
262
    /**
263
     * Set the message queue session.
264
     *
265
     * @param \AppserverIo\Messaging\QueueSession $session The  message queue session to set.
266
     *
267
     * @return void
268
     */
269
    public function setSession($session)
270
    {
271
        $this->session = $session;
272
    }
273
274
    /**
275
     * Handle the send request.
276
     *
277
     * @param \AppserverIo\Stomp\Frame $stompFrame The Stomp frame to handle the connect.
278
     *
279
     * @return void
280
     *
281
     * @throws \AppserverIo\Stomp\Exception\ProtocolException
282
     */
283
    protected function handleSend(Frame $stompFrame)
284
    {
285
        // checks ist the client authenticated
286
        if ($this->getAuthenticator()->getIsAuthenticated() === false) {
287
            throw new ProtocolException(sprintf(ErrorMessages::FAILED_AUTH, ""));
288
        }
289
290
        // set the destination from the header
291
        $destination = $stompFrame->getHeaderValueByKey(Headers::DESTINATION);
292
293
        // initialize the connection and the session
294
        $queue = MessageQueue::createQueue($destination);
295
296
        // create the sender and send a simple string message
297
        $sender = $this->getSession()->createSender($queue);
298
299
        // push the message in the que
300
        $sender->send(new StringMessage($stompFrame->getBody()));
301
    }
302
303
    /**
304
     * Handle the disconnect request.
305
     *
306
     * @param \AppserverIo\Stomp\Frame $stompFrame The Stomp frame to handle the connect.
307
     *
308
     * @return \AppserverIo\Stomp\Frame The stomp frame Response
309
     */
310
    protected function handleDisConnect($stompFrame)
311
    {
312
        $headers = array();
313
314
        // set the client a receiptId than must server must add this to response header
315
        $receiptId = $stompFrame->getHeaderValueByKey(Headers::RECEIPT_REQUESTED);
316
        if (is_string($receiptId)) {
317
            $headers = array(Headers::RECEIPT_ID => $receiptId);
318
        }
319
320
        // set state to close the client connection
321
        $this->mustConnectionClose = true;
322
323
        // returns the response frame
324
        return new Frame(ServerCommands::RECEIPT, $headers);
325
    }
326
327
    /**
328
     * Returns the response stomp frame.
329
     *
330
     * @return \AppserverIo\Stomp\Frame
331
     */
332
    public function getResponseStompFrame()
333
    {
334
        return $this->response;
335
    }
336
337
    /**
338
     * Sets the state from handler to error
339
     *
340
     * @param string $message The message to set in the error frame.
341
     * @param array  $headers The header to set in the error frame.
342
     *
343
     * @return mixed
344
     */
345
    public function setErrorState($message = "", $headers = array())
346
    {
347
        $this->response = $this->handleError($message, $headers);
348
    }
349
350
    /**
351
     * Returns error stomp frame.
352
     *
353
     * @param string $message The message to set
354
     * @param array  $headers The headers to set
355
     *
356
     * @return \AppserverIo\Stomp\Frame
357
     */
358
    protected function handleError($message, array $headers = array())
359
    {
360
        // set the default header
361
        if (count($headers) == 0) {
362
            $headers = array(Headers::CONTENT_TYPE => CommonValues::TEXT_PLAIN);
363
        }
364
365
        // set state to close the client connection
366
        $this->mustConnectionClose = true;
367
368
        // returns the response frame
369
        return new Frame(ServerCommands::ERROR, $headers, $message);
370
    }
371
}
372