protected function cron()
    {
        if (empty($this->params['jobs']) || !is_array($this->params['jobs'])) {
            throw new ShopgateLibraryException(ShopgateLibraryException::PLUGIN_API_CRON_NO_JOBS);
        }

        $unknownJobs = $this->getUnknownCronJobs($this->params['jobs']);
        if (!empty($unknownJobs)) {
            throw new ShopgateLibraryException(
                ShopgateLibraryException::PLUGIN_CRON_UNSUPPORTED_JOB,
                implode(', ', $unknownJobs),
                true
            );
        }

        // time tracking
        $starttime = microtime(true);

        // references
        $message    = '';
        $errorcount = 0;

        // execute the jobs
        foreach ($this->params['jobs'] as $job) {
            if (empty($job['job_params'])) {
                $job['job_params'] = array();
            }

            try {
                $jobErrorcount = 0;

                // job execution
                $this->plugin->cron($job['job_name'], $job['job_params'], $message, $jobErrorcount);

                // check error count
                if ($jobErrorcount > 0) {
                    $message    .= "{$jobErrorcount} errors occured while executing cron job '{$job['job_name']}'\n";
                    $errorcount += $jobErrorcount;
                }
            } catch (Exception $e) {
                $errorcount++;
                $message .= 'Job aborted: "' . $e->getMessage() . '"';
            }
        }

        // time tracking
        $endtime = microtime(true);
        $runtime = $endtime - $starttime;
        $runtime = round($runtime, 4);

        // prepare response
        $responses                          = array();
        $responses['message']               = $message;
        $responses['execution_error_count'] = $errorcount;
        $responses['execution_time']        = $runtime;

        if (empty($this->response)) {
            $this->response = new ShopgatePluginApiResponseAppJson($this->trace_id);
        }
        $this->responseData = $responses;
    }