public function executeCommand(ProcessEngine $engine) { $name = $this->builder->getName(); if ($this->builder->count() < 1) { throw new \RuntimeException(sprintf('Cannot deploy "%s" because it does not contain any resources', $name)); } $id = UUID::createRandom(); $sql = "\tINSERT INTO `#__bpmn_deployment`\n\t\t\t\t\t\t(`id`, `name`, `deployed_at`)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t(:id, :name, :time)\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $id); $stmt->bindValue('name', $name); $stmt->bindValue('time', time()); $stmt->execute(); $engine->info('Created deployment "{name}" with identifier <{id}>', ['name' => $name, 'id' => (string) $id]); $sql = "\tINSERT INTO `#__bpmn_resource`\n\t\t\t\t\t\t(`id`, `deployment_id`, `name`, `data`)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t(:id, :deployment, :name, :data)\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('deployment', $id); $parser = new DiagramLoader(); foreach ($this->builder as $name => $stream) { $in = $stream->getContents(); $resourceId = UUID::createRandom(); $stmt->bindValue('id', $resourceId); $stmt->bindValue('name', $name); $stmt->bindValue('data', new BinaryData($in)); $stmt->execute(); $engine->debug('Deployed resource "{name}" with identifer <{resourceId}>', ['name' => $name, 'resourceId' => (string) $resourceId]); if ($this->builder->isProcessResource($name)) { foreach ($parser->parseDiagramString($in) as $process) { $engine->pushCommand(new DeployBusinessProcessCommand($process, $id, $resourceId)); } } } return $id; }
/** * Create a new lock info value object. * * @param string $rootPath The path of the lock root (the locked resource when depth = 0) within the storage. * @param \DateTimeInterface $expires Expiry-date of this lock. * @param string $depth The lock depth, can be 0 or infinity. * @param integer $scope The lock scope, can be exclusive or shared. * @param string $owner The owner of the lock, can be an arbitrary string or a URI. */ public function __construct($rootPath, \DateTimeInterface $expires, $depth = self::DEPTH_INFINITY, $scope = self::SCOPE_EXCLUSIVE, $owner = '') { $this->rootPath = '/' . trim($rootPath, '/'); $this->depth = (string) $depth; $this->expires = new \DateTimeImmutable('@' . $expires->getTimestamp(), $expires->getTimezone()); $this->scope = $scope; $this->owner = trim($owner); $this->token = UUID::createRandom(); }
public function executeCommand(ProcessEngine $engine) { $sql = "\tSELECT `revision`\r\n\t\t\t\t\tFROM `#__bpmn_process_definition`\r\n\t\t\t\t\tWHERE `process_key` = :key\r\n\t\t\t\t\tORDER BY `revision` DESC\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('key', $this->builder->getKey()); $stmt->setLimit(1); $stmt->execute(); $revision = $stmt->fetchNextColumn(0); $model = $this->builder->build(); $id = $model->getId(); $time = time(); $sql = "\tINSERT INTO `#__bpmn_process_definition`\r\n\t\t\t\t\t\t(`id`, `deployment_id`, `resource_id`, `process_key`, `revision`, `definition`, `name`, `deployed_at`)\r\n\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t(:id, :deployment, :resource, :key, :revision, :model, :name, :deployed)\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $id); $stmt->bindValue('deployment', $this->deploymentId); $stmt->bindValue('resource', $this->resourceId); $stmt->bindValue('key', $this->builder->getKey()); $stmt->bindValue('revision', $revision + 1); $stmt->bindValue('model', new BinaryData(serialize($model), 3)); $stmt->bindValue('name', $model->getTitle()); $stmt->bindValue('deployed', $time); $stmt->execute(); $sql = "\tDELETE FROM `#__bpmn_process_subscription`\r\n\t\t\t\t\tWHERE `definition_id` IN (\r\n\t\t\t\t\t\tSELECT `id`\r\n\t\t\t\t\t\tFROM `#__bpmn_process_definition`\r\n\t\t\t\t\t\tWHERE `process_key` = :key\r\n\t\t\t\t\t)\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('key', $this->builder->getKey()); $stmt->execute(); $engine->info('Deployed business process {key} revision {revision} using id {id}', ['key' => $this->builder->getKey(), 'revision' => $revision + 1, 'id' => (string) $id]); foreach ($model->findStartNodes() as $node) { $behavior = $node->getBehavior(); if ($behavior instanceof MessageStartEventBehavior && !$behavior->isSubProcessStart()) { $sql = "\tINSERT INTO `#__bpmn_process_subscription`\r\n\t\t\t\t\t\t\t\t(`id`, `definition_id`, `flags`, `name`)\r\n\t\t\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t\t\t(:id, :def, :flags, :message)\r\n\t\t\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', UUID::createRandom()); $stmt->bindValue('def', $id); $stmt->bindValue('flags', EventSubscription::TYPE_MESSAGE); $stmt->bindValue('message', $behavior->getMessageName()); $stmt->execute(); $engine->debug('Process {process} subscribed to message <{message}>', ['process' => $this->builder->getKey(), 'message' => $behavior->getMessageName()]); } if ($behavior instanceof SignalStartEventBehavior && !$behavior->isSubProcessStart()) { $sql = "\tINSERT INTO `#__bpmn_process_subscription`\r\n\t\t\t\t\t\t\t\t(`id`, `definition_id`, `flags`, `name`)\r\n\t\t\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t\t\t(:id, :def, :flags, :message)\r\n\t\t\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', UUID::createRandom()); $stmt->bindValue('def', $id); $stmt->bindValue('flags', EventSubscription::TYPE_SIGNAL); $stmt->bindValue('message', $behavior->getSignalName()); $stmt->execute(); $engine->debug('Process {process} subscribed to signal <{signal}>', ['process' => $this->builder->getKey(), 'signal' => $behavior->getSignalName()]); } } return new ProcessDefinition($id, $this->builder->getKey(), $revision + 1, $model, $model->getTitle(), new \DateTimeImmutable('@' . $time), $this->deploymentId); }
public function __construct(array $items, $title = '', UUID $id = NULL) { $this->id = $id === NULL ? UUID::createRandom() : $id; $this->title = trim($title); foreach ($items as $item) { if ($item instanceof Node) { if (NULL === $item->getBehavior()) { throw new \RuntimeException(sprintf('Node "%s" does not declare a behavior', $item->getId())); } } } $this->items = $items; }
/** * Boots a DI container to be used during integration testing, you have to call * the parent method if you implement your own setup method. */ protected function setUp() { if (self::$testRunId === NULL) { self::$testRunId = (string) UUID::createRandom(); } $this->systemSettings['id'] = self::$testRunId; parent::setUp(); chdir(dirname((new \ReflectionClass(get_class($this)))->getFileName())); $this->setUpRules(); $this->createTestKernel(); foreach ($this->findRules() as $rule) { $rule->before($this); } }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $id = UUID::createRandom(); $execution = $engine->findExecution($this->executionId); $delegation = []; if ($this->nodeId !== NULL) { $delegation['nodeId'] = $this->nodeId; } $command = new SignalExecutionCommand($execution, NULL, [], $delegation); $job = $engine->scheduleJob($execution->getId(), AsyncCommandHandler::HANDLER_TYPE, [AsyncCommandHandler::PARAM_COMMAND => $command], new \DateTimeImmutable('@' . $this->time, new \DateTimeZone('UTC'))); $this->createSubscription($engine, $job); $engine->debug('{execution} subscribed to timer job <{job}>', ['execution' => (string) $execution, 'job' => $job === NULL ? 'NULL' : (string) $job->getId()]); return $id; }
protected function setupRootDirectory() { if (isset($this->settings['id'])) { $dir = static::computeRootDirectory($this->settings['id']); } else { $dir = Filesystem::createDirectory(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'k2' . DIRECTORY_SEPARATOR . UUID::createRandom()); } if (empty($this->settings['persistent'])) { register_shutdown_function(function () use($dir) { if (is_dir($dir)) { @Filesystem::removeDirectory($dir); } }); } return $dir; }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $def = $engine->getRepositoryService()->createProcessDefinitionQuery()->processDefinitionId($this->definitionId)->findOne(); $definition = $def->getModel(); $startNode = $definition->findNode($this->startNodeId); $process = new VirtualExecution(UUID::createRandom(), $engine, $definition); $process->setBusinessKey($this->businessKey); $process->setNode($startNode); foreach (unserialize($this->variables) as $k => $v) { $process->setVariable($k, $v); } $engine->registerExecution($process); $engine->info('Started {process} using process definition "{key}" ({id})', ['process' => (string) $process, 'key' => $def->getKey(), 'id' => (string) $def->getId()]); $process->execute($startNode); return $process->getId(); }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $id = UUID::createRandom(); $activityId = NULL; if ($this->executionId !== NULL) { $activityId = $engine->findExecution($this->executionId)->getNode()->getId(); } $sql = "\tINSERT INTO `#__bpmn_user_task`\r\n\t\t\t\t\t\t(`id`, `execution_id`, `name`, `documentation`, `activity`, `created_at`, `priority`, `due_at`)\r\n\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t(:id, :eid, :name, :doc, :activity, :created, :priority, :due)\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $id); $stmt->bindValue('eid', $this->executionId); $stmt->bindValue('name', $this->name); $stmt->bindValue('doc', $this->documentation); $stmt->bindValue('activity', $activityId); $stmt->bindValue('created', time()); $stmt->bindValue('priority', $this->priority); $stmt->bindValue('due', $this->dueDate); $stmt->execute(); $engine->debug('Created user task "{task}" with id {id}', ['task' => $this->name, 'id' => (string) $id]); $task = $engine->getTaskService()->createTaskQuery()->taskId($id)->findOne(); $engine->notify(new UserTaskCreatedEvent($task, $engine)); return $task; }
public function refreshLock(ResourceInterface $resource, UUID $token, \DateTimeInterface $expires = NULL) { $expires = $this->computeExpires($expires); $sql = "\tUPDATE `#__webdav_lock`\n\t\t\t\t\tSET `expires_at` = :expires\n\t\t\t\t\tWHERE `token` = :token\n\t\t\t\t\tAND `expires_at` > :time\n\t\t"; $stmt = $this->conn->prepare($sql); $stmt->bindValue('expires', $expires->getTimestamp()); $stmt->bindValue('token', $token->toBinary()); $stmt->bindValue('time', time()); if (1 != $stmt->execute()) { throw new \RuntimeException(sprintf('Unable to refresh lock "%s"', $token)); } $sql = "SELECT * FROM `#__webdav_lock` WHERE `token` = :token"; $stmt = $this->conn->prepare($sql); $stmt->bindValue('token', $token->toBinary()); $stmt->execute(); if (false === ($row = $stmt->fetchNextRow())) { throw new \RuntimeException(sprintf('Failed during retrieva of refreshed lock "%s"', $token)); } $lock = new LockInfo($resource->getPath(), new \DateTimeImmutable('@' . $row['expires_at']), LockInfo::DEPTH_0, LockInfo::SCOPE_EXCLUSIVE, $row['owner']); $lock->setToken($row['token']); return $lock; }
public function __construct(TransactionInterface $parent = NULL) { $this->parent = $parent; $this->identifier = 'T' . substr(str_replace('-', '', UUID::createRandom()), 0, 29); $this->resources = new \SplObjectStorage(); }
public function build() { $model = $this->builder->build(); $linkCatch = []; $linkThrow = []; foreach ($model->findNodes() as $node) { $behavior = $node->getBehavior(); if ($behavior instanceof IntermediateLinkCatchBehavior) { $linkCatch[$behavior->getLink()] = $node->getId(); } if ($behavior instanceof IntermediateLinkThrowBehavior) { $linkThrow[$node->getId()] = $behavior->getLink(); } } if (!empty($linkCatch)) { foreach ($linkThrow as $nodeId => $link) { if (empty($linkCatch[$link])) { throw new \RuntimeException(sprintf('No link catch event defined for link "%s" thrown by node %s', $link, $nodeId)); } // This does the trick: insert a new transition directly connecting the link events. $trans = new Transition('link-' . UUID::createRandom(), $nodeId); $trans->to($linkCatch[$link]); $model->addItem($trans); } } return $model; }
public function __construct(DuplexStreamInterface $socket, LoggerInterface $logger = NULL) { $this->id = (string) UUID::createRandom(); $this->socket = $socket; $this->logger = $logger; }
/** * Introduce a new concurrent root as parent of this execution. * * @param boolean $active * @return Execution */ public function introduceConcurrentRoot($active = false) { $this->engine->debug('Introducing concurrent root into {execution}', ['execution' => (string) $this]); $parent = $this->parentExecution; $root = new static(UUID::createRandom(), $this->engine, $this->model, $parent); $root->setActive($active); $root->variables = $this->variables; $root->setState(self::STATE_SCOPE, $this->isScope()); if ($parent !== NULL) { foreach ($parent->childExecutions as $index => $exec) { if ($exec === $this) { unset($parent->childExecutions[$index]); } } } $this->setParentExecution($root); $this->setState(self::STATE_CONCURRENT, true); $this->setState(self::STATE_SCOPE, false); $this->variables = []; $this->markModified(); $this->engine->registerExecution($root); return $root; }
/** * Create an event subscription entry in the DB. * * @param ProcessEngine $engine * @param Job $job */ protected function createSubscription(ProcessEngine $engine, Job $job = NULL) { $execution = $engine->findExecution($this->executionId); $nodeId = $this->nodeId === NULL ? NULL : $execution->getProcessModel()->findNode($this->nodeId)->getId(); $data = ['id' => UUID::createRandom(), 'execution_id' => $execution->getId(), 'activity_id' => $this->activityId, 'node' => $nodeId, 'process_instance_id' => $execution->getRootExecution()->getId(), 'flags' => $this->getSubscriptionFlag(), 'boundary' => $this->boundaryEvent ? 1 : 0, 'name' => $this->name, 'created_at' => time()]; if ($job !== NULL) { $data['job_id'] = $job->getId(); } $engine->getConnection()->insert('#__bpmn_event_subscription', $data); }
public function createLock(ResourceInterface $resource, \DateTimeInterface $expires = NULL, $owner = NULL) { $stmt = $this->lockStore->prepare('SELECT COUNT(*) FROM "file_locks" WHERE `id` = :token'); do { $token = UUID::createRandom(); $stmt->bindValue('token', (string) $token); $stmt->execute(); $found = $stmt->fetch(\PDO::FETCH_COLUMN, 0); } while ($found); $expires = $this->computeExpires($expires); $path = trim($resource->getPath(), '/'); $sql = ' INSERT OR REPLACE INTO "file_locks" ("id", "resource", "locked", "expires", "owner") VALUES (:id, :resource, :locked, :expires, :owner) '; $stmt = $this->lockStore->prepare($sql); $stmt->bindValue('id', (string) $token); $stmt->bindValue('resource', $path); $stmt->bindValue('locked', time()); $stmt->bindValue('expires', $expires->getTimestamp()); $stmt->bindValue('owner', $owner); $stmt->execute(); $lock = new LockInfo($path, $expires, LockInfo::DEPTH_0, LockInfo::SCOPE_EXCLUSIVE, $owner); $lock->setToken($token); return $lock; }
protected function createRootExecution(EngineInterface $engine) { return new Execution(UUID::createRandom(), $engine, $this->model); }
/** * {@inheritdoc} */ public function scheduleJob(UUID $executionId, $handlerType, $data, \DateTimeInterface $runAt = NULL) { $id = UUID::createRandom(); $handlerType = (string) $handlerType; $job = new Job($id, $executionId, $handlerType, $data); $job->setRunAt($runAt); $time = $job->getRunAt(); if ($time !== NULL) { $time = $time->getTimestamp(); } $this->engine->getConnection()->insert('#__bpmn_job', ['id' => $job->getId(), 'execution_id' => $job->getExecutionId(), 'handler_type' => $job->getHandlerType(), 'handler_data' => new BinaryData(serialize($job->getHandlerData())), 'created_at' => time(), 'run_at' => $time]); $this->engine->info('Created job <{job}> of type "{handler}" targeting execution <{execution}>', ['job' => (string) $job->getId(), 'handler' => $handlerType, 'execution' => (string) $executionId]); return $this->scheduledJobs[] = $job; }
protected function recordActivityStarted(ActivityStartedEvent $event) { $this->engine->getConnection()->insert('#__bpmn_history_activity', ['id' => UUID::createRandom(), 'process_id' => $event->execution->getRootExecution()->getId(), 'activity' => $event->name, 'started_at' => DateTimeMillisTransformer::encode($event->timestamp)]); }
protected function setupRootDirectory() { $dir = Filesystem::createDirectory(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'k2' . DIRECTORY_SEPARATOR . UUID::createRandom()); // TODO: Directory is not being removed when console is terminated using CRTL+C kill signal... register_shutdown_function(function () use($dir) { if (is_dir($dir)) { @Filesystem::removeDirectory($dir); } }); return $dir; }