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;
 }
Beispiel #2
0
 /**
  * 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);
 }
Beispiel #4
0
 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;
 }
Beispiel #5
0
 /**
  * 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;
 }
Beispiel #7
0
 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;
 }
Beispiel #10
0
 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;
 }
Beispiel #11
0
 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;
 }
Beispiel #13
0
 public function __construct(DuplexStreamInterface $socket, LoggerInterface $logger = NULL)
 {
     $this->id = (string) UUID::createRandom();
     $this->socket = $socket;
     $this->logger = $logger;
 }
Beispiel #14
0
 /**
  * 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);
 }
Beispiel #16
0
    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);
 }
Beispiel #18
0
 /**
  * {@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;
 }
Beispiel #19
0
 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)]);
 }
Beispiel #20
0
 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;
 }