<?php /** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; under version 2 * of the License (non-upgradable). * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2017 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); * */ namespace oat\taoTaskQueue\model\QueueBroker; use oat\oatbox\PhpSerializable; use oat\oatbox\service\ConfigurableService; use oat\oatbox\action\ActionService; use oat\oatbox\action\ResolutionException; use oat\oatbox\log\LoggerAwareTrait; use oat\taoTaskQueue\model\QueueDispatcher; use oat\taoTaskQueue\model\Task\CallbackTaskInterface; use oat\taoTaskQueue\model\Task\TaskFactory; use oat\taoTaskQueue\model\Task\TaskInterface; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorAwareTrait; /** * Class AbstractQueueBroker * * @deprecated Use \oat\tao\model\taskQueue\Queue\Broker\AbstractQueueBroker * * @author Gyula Szucs <gyula@taotesting.com> */ abstract class AbstractQueueBroker implements QueueBrokerInterface, PhpSerializable, ServiceLocatorAwareInterface { use LoggerAwareTrait; use ServiceLocatorAwareTrait; private $numberOfTasksToReceive; private $queueName; private $preFetchedQueue; /** * AbstractMessageBroker constructor. * * @param int $receiveTasks Maximum amount of tasks that can be received when polling the queue; Default is 1. */ public function __construct($receiveTasks = 1) { $this->numberOfTasksToReceive = $receiveTasks; $this->preFetchedQueue = new \SplQueue(); } public function __toPhpCode() { return 'new ' . get_called_class() . '(' . \common_Utils::toHumanReadablePhpString($this->numberOfTasksToReceive) . ')'; } /** * Do the specific pop mechanism related to the given broker. * Tasks need to be added to the internal pre-fetched queue. * * @return void */ abstract protected function doPop(); /** * Internal mechanism of deleting a message, specific for the given broker * * @param string $id * @param array $logContext * @return void */ abstract protected function doDelete($id, array $logContext = []); /** * @return null|TaskInterface */ public function pop() { // if there is item in the pre-fetched queue, let's return that if ($message = $this->popPreFetchedMessage()) { return $message; } $this->doPop(); return $this->popPreFetchedMessage(); } /** * Pop a task from the internal queue. * * @return TaskInterface|null */ private function popPreFetchedMessage() { if ($this->preFetchedQueue->count()) { return $this->preFetchedQueue->dequeue(); } return null; } /** * Add a task to the internal queue. * * @param TaskInterface $task */ protected function pushPreFetchedMessage(TaskInterface $task) { $this->preFetchedQueue->enqueue($task); } /** * Unserialize the given task JSON. * * If the json is not valid, it deletes the task straight away without processing it. * * @param string $taskJSON * @param string $idForDeletion An identification of the given task * @param array $logContext * @return null|TaskInterface */ protected function unserializeTask($taskJSON, $idForDeletion, array $logContext = []) { try { $basicData = json_decode($taskJSON, true); $this->assertValidJson($basicData); $task = TaskFactory::build($basicData); if ($task instanceof CallbackTaskInterface && is_string($task->getCallable())) { $this->handleCallbackTask($task, $logContext); } return $task; } catch (\Exception $e) { $this->doDelete($idForDeletion, $logContext); return null; } } /** * @param TaskInterface $task * @return mixed */ protected function serializeTask(TaskInterface $task) { return json_encode($task); } /** * @param $basicData * @throws \Exception */ protected function assertValidJson($basicData) { if ( ($basicData !== null && json_last_error() === JSON_ERROR_NONE && isset($basicData[TaskInterface::JSON_TASK_CLASS_NAME_KEY])) === false ) { throw new \Exception(); } } /** * @param CallbackTaskInterface $task * @param array $logContext * @throws \Exception */ protected function handleCallbackTask(CallbackTaskInterface $task, array $logContext) { try { $callable = $this->getActionResolver()->resolve($task->getCallable()); if ($callable instanceof ServiceLocatorAwareInterface) { $callable->setServiceLocator($this->getServiceLocator()); } $task->setCallable($callable); } catch (ResolutionException $e) { $this->logError('Callable/Action class ' . $task->getCallable() . ' does not exist', $logContext); throw new \Exception(); } } /** * @return ActionService|ConfigurableService|object */ protected function getActionResolver() { return $this->getServiceLocator()->get(ActionService::SERVICE_ID); } /** * @param string $name * @return $this */ public function setQueueName($name) { $this->queueName = $name; return $this; } /** * @return string */ protected function getQueueName() { return $this->queueName; } /** * @return string */ protected function getQueueNameWithPrefix() { return sprintf("%s_%s", QueueDispatcher::QUEUE_PREFIX, $this->getQueueName()); } /** * @inheritdoc */ public function getNumberOfTasksToReceive() { return abs((int) $this->numberOfTasksToReceive); } }