/** * Start server * * @param string[] args */ public static function main(array $args) { $stor = new TestingStorage(); $stor->add(new TestingCollection('/', $stor)); $stor->add(new TestingCollection('/.trash', $stor)); $stor->add(new TestingElement('/.trash/do-not-remove.txt', $stor)); $stor->add(new TestingCollection('/htdocs', $stor)); $stor->add(new TestingElement('/htdocs/file with whitespaces.html', $stor)); $stor->add(new TestingElement('/htdocs/index.html', $stor, "<html/>\n")); $stor->add(new TestingCollection('/outer', $stor)); $stor->add(new TestingCollection('/outer/inner', $stor)); $stor->add(new TestingElement('/outer/inner/index.html', $stor)); $auth = newinstance('lang.Object', array(), '{ public function authenticate($user, $password) { return ("testtest" == $user.$password); } }'); $protocol = newinstance('peer.ftp.server.FtpProtocol', array($stor, $auth), '{ public function onShutdown($socket, $params) { $this->answer($socket, 200, "Shutting down"); $this->server->terminate= TRUE; } }'); isset($args[0]) && $protocol->setTrace(Logger::getInstance()->getCategory()->withAppender(new FileAppender($args[0]))); $s = new Server('127.0.0.1', 0); try { $s->setProtocol($protocol); $s->init(); Console::writeLinef('+ Service %s:%d', $s->socket->host, $s->socket->port); $s->service(); Console::writeLine('+ Done'); } catch (\lang\Throwable $e) { Console::writeLine('- ', $e->getMessage()); } }
public function setUp() { if (null === $this->host) { throw new PrerequisitesNotMetError('Needs argument "host"'); } $this->fixture = new Connection(new \peer\URL('stomp://' . $this->host)); $this->fixture->setTrace(\util\log\Logger::getInstance()->getCategory()); $this->fixture->connect('system', 'manager'); }
/** * Entry point method. Receives the following arguments from xpws: * * - The web root - defaults to $CWD * - The configuration directory - defaults to "etc" * - The server profile - default to "dev" * - The server address - default to "localhost:8080" * - The mode - default to "serve" * * @param string[] args * @return int */ public static function main(array $args) { $webroot = isset($args[0]) ? realpath($args[0]) : getcwd(); $configd = isset($args[1]) ? $args[1] : 'etc'; $profile = isset($args[2]) ? $args[2] : 'dev'; $address = isset($args[3]) ? $args[3] : 'localhost:8080'; if (!($class = @self::$modes[isset($args[4]) ? $args[4] : 'serve'])) { Console::writeLine('*** Unkown server mode "', $args[4], '", supported: ', self::$modes); return 2; } $expand = function ($in) use($webroot, $profile) { return strtr($in, array('{WEBROOT}' => $webroot, '{PROFILE}' => $profile, '{DOCUMENT_ROOT}' => getenv('DOCUMENT_ROOT'))); }; Console::writeLine('---> Startup ', $class, '(', $address, ')'); sscanf($address, '%[^:]:%d', $host, $port); $server = XPClass::forName($class)->newInstance($host, $port); with($pm = PropertyManager::getInstance(), $protocol = $server->setProtocol(new HttpProtocol())); $conf = new WebConfiguration(new \util\Properties($configd . DIRECTORY_SEPARATOR . 'web.ini')); $resources = $conf->staticResources($args[2]); if (null === $resources) { $protocol->setUrlHandler('default', '#^/#', new FileHandler($expand('{DOCUMENT_ROOT}'), $notFound = function () { return HttpConstants::STATUS_CONTINUE; })); } else { foreach ($conf->staticResources($args[2]) as $pattern => $location) { $protocol->setUrlHandler('default', '#' . strtr($pattern, array('#' => '\\#')) . '#', new FileHandler($expand($location))); } } foreach ($conf->mappedApplications($args[2]) as $url => $application) { foreach (explode('|', $application->getConfig()) as $element) { $expanded = $expand($element); if (0 == strncmp('res://', $expanded, 6)) { $pm->appendSource(new ResourcePropertySource(substr($expanded, 6))); } else { $pm->appendSource(new FilesystemPropertySource($expanded)); } } $protocol->setUrlHandler('default', '/' == $url ? '##' : '#^(' . preg_quote($url, '#') . ')($|/.+)#', new ScriptletHandler($application->getScriptlet(), array_map($expand, $application->getArguments()), array_map($expand, array_merge($application->getEnvironment(), array('DOCUMENT_ROOT' => getenv('DOCUMENT_ROOT')))))); } $l = Logger::getInstance(); $pm->hasProperties('log') && $l->configure($pm->getProperties('log')); $cm = ConnectionManager::getInstance(); $pm->hasProperties('database') && $cm->configure($pm->getProperties('database')); Console::writeLine($protocol); $server->init(); Console::writeLine('===> Server started'); $server->service(); $server->shutdown(); return 0; }
/** * Update method * * @param util.Observable obs * @param var arg default NULL */ public function update($obs, $arg = null) { if (!$obs instanceof DBConnection) { throw new \lang\IllegalArgumentException('Argument 1 must be instanceof "rdbms.DBConnection", "' . \xp::typeOf($obs) . '" given.'); } if (!$arg instanceof DBEvent) { return; } // Store reference for later reuse if (null === $this->cat) { $this->setTrace(Logger::getInstance()->getCategory($this->name)); } if (null === $this->dsn) { $this->dsn = $obs->getDSN()->withoutPassword(); } $method = $arg->getName(); switch ($method) { case 'query': case 'open': $this->lastq = $this->typeOf($arg->getArgument()); // Fallthrough intentional // Fallthrough intentional case 'connect': if ('connect' == $method) { $this->lastq = $method; } $this->timer = new Timer(); $this->timer->start(); // Count some well-known SQL keywords $this->countFor($this->lastq); break; case 'connected': case 'queryend': // Protect against illegal order of events (should not occur) if (!$this->timer) { return; } $this->timer->stop(); $this->addElapsedTimeTo($method, $this->timer->elapsedTime()); if ($this->lastq) { $this->addElapsedTimeTo($this->lastq, $this->timer->elapsedTime()); $this->lastq = null; } $this->timer = null; break; } }
/** * Constructor * * @param var $url either a URL object or a string * @throws lang.IllegalArgumentException if string given is unparseable */ public function __construct($url) { if ($url instanceof Failover) { $this->failover = $url; } else { $this->failover = Failover::using([$url])->byRandom(); } // Walk through all failover members, to check they all have valid URLs; by returning // false, indicate to failover to the next available member. // For BC reasons, if one connection has a log=<category> parameter, read it // and set it into this objects $cat member. $this->failover->elect(function ($url) { $url = self::urlFrom($url); if (!$this->cat && $url->hasParam('log')) { $this->setTrace(Logger::getInstance()->getCategory($url->getParam('log'))); } return false; }); }
/** * Serve requests * * @param string $source * @param string $profile * @param io.Path $webroot * @param io.Path $docroot * @param string[] $config */ public function serve($source, $profile, $webroot, $docroot, $config) { $this->server->init(); $protocol = $this->server->setProtocol(new HttpProtocol(function ($host, $method, $query, $status, $error) { Console::writeLinef(" [33m[%s %d %.3fkB][0m %d %s %s", date('Y-m-d H:i:s'), getmypid(), memory_get_usage() / 1024, $status, $method, $query, $error); })); $pm = PropertyManager::getInstance(); $expand = function ($in) use($webroot, $profile, $docroot) { return is_string($in) ? strtr($in, ['{WEBROOT}' => $webroot, '{PROFILE}' => $profile, '{DOCUMENT_ROOT}' => $docroot]) : $in; }; $layout = (new Source($source, new Config($config, $expand)))->layout(); Console::writeLine("[33m@", $this, "[0m"); Console::writeLine("[1mServing ", $layout); Console::writeLine("[36m", str_repeat('═', 72), "[0m"); Console::writeLine(); $resources = $layout->staticResources($profile); if (null === $resources) { $protocol->setUrlHandler('default', '#^/#', new FileHandler($docroot, $notFound = function () { return null; })); } else { foreach ($resources as $pattern => $location) { $protocol->setUrlHandler('default', '#' . strtr($pattern, ['#' => '\\#']) . '#', new FileHandler($expand($location))); } } foreach ($layout->mappedApplications($profile) as $url => $application) { $protocol->setUrlHandler('default', '/' === $url ? '##' : '#^(' . preg_quote($url, '#') . ')($|/.+)#', new ScriptletHandler($application->scriptlet(), array_map($expand, $application->arguments()), array_map($expand, array_merge($application->environment(), ['DOCUMENT_ROOT' => $docroot])), $application->filters())); foreach ($application->config()->sources() as $s) { $pm->appendSource($s); } } $l = Logger::getInstance(); $pm->hasProperties('log') && $l->configure($pm->getProperties('log')); $cm = ConnectionManager::getInstance(); $pm->hasProperties('database') && $cm->configure($pm->getProperties('database')); Console::writeLine("[33;1m>[0m Server started: [35;4m", $this->url, "[0m (", date('r'), ')'); Console::writeLine(' PID ', getmypid(), '; press Ctrl+C to exit'); Console::writeLine(); $this->server->service(); $this->server->shutdown(); }
public function loggerIsASingleton() { $this->assertTrue($this->logger === Logger::getInstance()); }
/** * Creates the scriptlet instance for the given URL and runs it * * @param string url default '/' */ public function run($url = '/') { // Determine which scriptlet should be run $application = $this->applicationAt($url); // Determine debug level $flags = $application->getDebug(); // Initializer logger, properties and connections to property base, // defaulting to the same directory the web.ini resides in $pm = PropertyManager::getInstance(); foreach (explode('|', $application->getConfig()) as $element) { $expanded = $this->expand($element); if (0 == strncmp('res://', $expanded, 6)) { $pm->appendSource(new ResourcePropertySource($expanded)); } else { $pm->appendSource(new FilesystemPropertySource($expanded)); } } $l = Logger::getInstance(); $pm->hasProperties('log') && $l->configure($pm->getProperties('log')); $cm = ConnectionManager::getInstance(); $pm->hasProperties('database') && $cm->configure($pm->getProperties('database')); // Setup logger context for all registered log categories foreach (Logger::getInstance()->getCategories() as $category) { if (null === ($context = $category->getContext()) || !$context instanceof EnvironmentAware) { continue; } $context->setHostname($_SERVER['SERVER_NAME']); $context->setRunner($this->getClassName()); $context->setInstance($application->getScriptlet()); $context->setResource($url); $context->setParams($_SERVER['QUERY_STRING']); } // Set environment variables foreach ($application->getEnvironment() as $key => $value) { $_SERVER[$key] = $this->expand($value); } // Instantiate and initialize $cat = $l->getCategory('scriptlet'); $instance = null; $e = null; try { $class = \lang\XPClass::forName($application->getScriptlet()); if (!$class->hasConstructor()) { $instance = $class->newInstance(); } else { $args = array(); foreach ($application->getArguments() as $arg) { $args[] = $this->expand($arg); } $instance = $class->getConstructor()->newInstance($args); } if ($flags & WebDebug::TRACE && $instance instanceof \util\log\Traceable) { $instance->setTrace($cat); } $instance->init(); // Service $response = $instance->process(); } catch (\scriptlet\ScriptletException $e) { $cat->error($e); // TODO: Instead of checking for a certain method, this should // check if the scriptlet class implements a certain interface if (method_exists($instance, 'fail')) { $response = $instance->fail($e); } else { $response = $this->fail($e, $e->getStatus(), $flags & WebDebug::STACKTRACE); } } catch (\lang\SystemExit $e) { if (0 === $e->getCode()) { $response = new \scriptlet\HttpScriptletResponse(); $response->setStatus(HttpConstants::STATUS_OK); if ($message = $e->getMessage()) { $response->setContent($message); } } else { $cat->error($e); $response = $this->fail($e, HttpConstants::STATUS_INTERNAL_SERVER_ERROR, false); } } catch (\lang\Throwable $e) { $cat->error($e); // Here, we might not have a scriptlet $response = $this->fail($e, HttpConstants::STATUS_PRECONDITION_FAILED, $flags & WebDebug::STACKTRACE); } // Send output $response->isCommitted() || $response->flush(); $response->sendContent(); // Call scriptlet's finalizer $instance && $instance->finalize(); // Debugging if ($flags & WebDebug::XML && isset($response->document)) { flush(); echo '<xmp>', $response->document->getDeclaration() . "\n" . $response->document->getSource(0), '</xmp>'; } if ($flags & WebDebug::ERRORS) { flush(); echo '<xmp>', $e ? $e->toString() : '', \xp::stringOf(\xp::$errors), '</xmp>'; } }
/** * Main method * * @param util.cmd.ParamString params * @return int */ public function run(ParamString $params) { // No arguments given - show our own usage if ($params->count < 1) { return self::usage(); } // Configure properties $pm = PropertyManager::getInstance(); // Separate runner options from class options for ($offset = 0, $i = 0; $i < $params->count; $i++) { switch ($params->list[$i]) { case '-c': if (0 == strncmp('res://', $params->list[$i + 1], 6)) { $pm->appendSource(new ResourcePropertySource(substr($params->list[$i + 1], 6))); } else { $pm->appendSource(new FilesystemPropertySource($params->list[$i + 1])); } $offset += 2; $i++; break; case '-cp': \lang\ClassLoader::registerPath($params->list[$i + 1], null); $offset += 2; $i++; break; case '-v': $this->verbose = true; $offset += 1; $i++; break; case '-?': return self::usage(); default: break 2; } } // Sanity check if (!$params->exists($offset)) { self::$err->writeLine('*** Missing classname'); return 1; } // Use default path for PropertyManager if no sources set if (!$pm->getSources()) { $pm->configure(self::DEFAULT_CONFIG_PATH); } unset($params->list[-1]); $classname = $params->value($offset); $classparams = new ParamString(array_slice($params->list, $offset + 1)); // Class file or class name if (strstr($classname, \xp::CLASS_FILE_EXT)) { $file = new \io\File($classname); if (!$file->exists()) { self::$err->writeLine('*** Cannot load class from non-existant file ', $classname); return 1; } try { $class = \lang\ClassLoader::getDefault()->loadUri($file->getURI()); } catch (\lang\ClassNotFoundException $e) { self::$err->writeLine('*** ', $this->verbose ? $e : $e->getMessage()); return 1; } } else { try { $class = \lang\XPClass::forName($classname); } catch (\lang\ClassNotFoundException $e) { self::$err->writeLine('*** ', $this->verbose ? $e : $e->getMessage()); return 1; } } // Check whether class is runnable if (!$class->isSubclassOf('lang.Runnable')) { self::$err->writeLine('*** ', $class->getName(), ' is not runnable'); return 1; } // Usage if ($classparams->exists('help', '?')) { self::showUsage($class); return 0; } // Load, instantiate and initialize $l = Logger::getInstance(); $pm->hasProperties('log') && $l->configure($pm->getProperties('log')); if (class_exists('rdbms\\DBConnection')) { // FIXME: Job of XPInjector? $cm = ConnectionManager::getInstance(); $pm->hasProperties('database') && $cm->configure($pm->getProperties('database')); } // Setup logger context for all registered log categories foreach (Logger::getInstance()->getCategories() as $category) { if (null === ($context = $category->getContext()) || !$context instanceof EnvironmentAware) { continue; } $context->setHostname(\lang\System::getProperty('host.name')); $context->setRunner(nameof($this)); $context->setInstance($class->getName()); $context->setResource(null); $context->setParams($params->string); } $instance = $class->newInstance(); $instance->in = self::$in; $instance->out = self::$out; $instance->err = self::$err; $methods = $class->getMethods(); // Injection foreach ($methods as $method) { if (!$method->hasAnnotation('inject')) { continue; } $inject = $method->getAnnotation('inject'); if (isset($inject['type'])) { $type = $inject['type']; } else { if ($restriction = $method->getParameter(0)->getTypeRestriction()) { $type = $restriction->getName(); } else { $type = $method->getParameter(0)->getType()->getName(); } } try { switch ($type) { case 'rdbms.DBConnection': $args = [$cm->getByHost($inject['name'], 0)]; break; case 'util.Properties': $p = $pm->getProperties($inject['name']); // If a PropertyAccess is retrieved which is not a util.Properties, // then, for BC sake, convert it into a util.Properties if ($p instanceof \util\PropertyAccess && !$p instanceof \util\Properties) { $convert = \util\Properties::fromString(''); $section = $p->getFirstSection(); while ($section) { // HACK: Properties::writeSection() would first attempts to // read the whole file, we cannot make use of it. $convert->_data[$section] = $p->readSection($section); $section = $p->getNextSection(); } $args = [$convert]; } else { $args = [$p]; } break; case 'util.log.LogCategory': $args = [$l->getCategory($inject['name'])]; break; default: self::$err->writeLine('*** Unknown injection type "' . $type . '" at method "' . $method->getName() . '"'); return 2; } $method->invoke($instance, $args); } catch (\lang\reflect\TargetInvocationException $e) { self::$err->writeLine('*** Error injecting ' . $type . ' ' . $inject['name'] . ': ' . $e->getCause()->compoundMessage()); return 2; } catch (\lang\Throwable $e) { self::$err->writeLine('*** Error injecting ' . $type . ' ' . $inject['name'] . ': ' . $e->compoundMessage()); return 2; } } // Arguments foreach ($methods as $method) { if ($method->hasAnnotation('args')) { // Pass all arguments if (!$method->hasAnnotation('args', 'select')) { $begin = 0; $end = $classparams->count; $pass = array_slice($classparams->list, 0, $end); } else { $pass = []; foreach (preg_split('/, ?/', $method->getAnnotation('args', 'select')) as $def) { if (is_numeric($def) || '-' == $def[0]) { $pass[] = $classparams->value((int) $def); } else { sscanf($def, '[%d..%d]', $begin, $end); isset($begin) || ($begin = 0); isset($end) || ($end = $classparams->count - 1); while ($begin <= $end) { $pass[] = $classparams->value($begin++); } } } } try { $method->invoke($instance, [$pass]); } catch (\lang\Throwable $e) { self::$err->writeLine('*** Error for arguments ' . $begin . '..' . $end . ': ', $this->verbose ? $e : $e->getMessage()); return 2; } } else { if ($method->hasAnnotation('arg')) { // Pass arguments $arg = $method->getAnnotation('arg'); if (isset($arg['position'])) { $name = '#' . ($arg['position'] + 1); $select = intval($arg['position']); $short = null; } else { if (isset($arg['name'])) { $name = $select = $arg['name']; $short = isset($arg['short']) ? $arg['short'] : null; } else { $name = $select = strtolower(preg_replace('/^set/', '', $method->getName())); $short = isset($arg['short']) ? $arg['short'] : null; } } if (0 == $method->numParameters()) { if (!$classparams->exists($select, $short)) { continue; } $args = []; } else { if (!$classparams->exists($select, $short)) { list($first, ) = $method->getParameters(); if (!$first->isOptional()) { self::$err->writeLine('*** Argument ' . $name . ' does not exist!'); return 2; } $args = []; } else { $args = [$classparams->value($select, $short)]; } } try { $method->invoke($instance, $args); } catch (\lang\reflect\TargetInvocationException $e) { self::$err->writeLine('*** Error for argument ' . $name . ': ', $this->verbose ? $e->getCause() : $e->getCause()->compoundMessage()); return 2; } } } } try { $instance->run(); } catch (\lang\Throwable $t) { self::$err->writeLine('*** ', $t->toString()); return 70; // EX_SOFTWARE according to sysexits.h } return 0; }
public function setDebug($d = FALSE) { if (NULL === $d) { Logger::getInstance()->getCategory()->withAppender(new ColoredConsoleAppender()); } }
/** * Creates the scriptlet instance for the given URL and runs it * * @param string $url default '/' */ public function run($url = '/') { // Determine which scriptlet should be run $application = $this->applicationAt($url); // Determine debug level $flags = $application->debug(); // Initializer logger, properties and connections to property base, // defaulting to the same directory the web.ini resides in $pm = PropertyManager::getInstance(); foreach ($application->config()->sources() as $source) { $pm->appendSource($source); } $l = Logger::getInstance(); $pm->hasProperties('log') && $l->configure($pm->getProperties('log')); $cm = ConnectionManager::getInstance(); $pm->hasProperties('database') && $cm->configure($pm->getProperties('database')); // Setup logger context for all registered log categories foreach (Logger::getInstance()->getCategories() as $category) { if (null === ($context = $category->getContext()) || !$context instanceof EnvironmentAware) { continue; } $context->setHostname($_SERVER['SERVER_NAME']); $context->setRunner(nameof($this)); $context->setInstance($application->getScriptlet()); $context->setResource($url); $context->setParams($_SERVER['QUERY_STRING']); } // Set environment variables foreach ($application->environment() as $key => $value) { $_SERVER[$key] = $this->expand($value); } // Instantiate and initialize $cat = $l->getCategory('scriptlet'); $instance = null; $e = null; try { if (!($class = $application->scriptlet())) { throw new IllegalStateException('No scriptlet in ' . $application->toString()); } if (!$class->hasConstructor()) { $instance = $class->newInstance(); } else { $args = []; foreach ($application->arguments() as $arg) { $args[] = $this->expand($arg); } $instance = $class->getConstructor()->newInstance($args); } if ($flags & WebDebug::TRACE && $instance instanceof \util\log\Traceable) { $instance->setTrace($cat); } foreach ($application->filters() as $filter) { $instance->filter($filter); } $instance->init(); // Set up request and response $request = $instance->request(); $request->method = $_SERVER['REQUEST_METHOD']; $request->env = $_ENV; $request->setHeaders(getallheaders()); $request->setParams($_REQUEST); $response = $instance->response(); // Service $instance->service($request, $response); } catch (ScriptletException $e) { if (isset($application->logLevels()[$e->getStatus()])) { $logLevel = $application->logLevels()[$e->getStatus()]; $cat->{$logLevel}($e); } else { $cat->error($e); } // TODO: Instead of checking for a certain method, this should // check if the scriptlet class implements a certain interface if (method_exists($instance, 'fail')) { $response = $instance->fail($e); } else { $this->error($response, $e, $e->getStatus(), $flags & WebDebug::STACKTRACE); } } catch (\lang\SystemExit $e) { if (0 === $e->getCode()) { $response->setStatus(HttpConstants::STATUS_OK); if ($message = $e->getMessage()) { $response->setProcessed(false); $response->setContent($message); } } else { $cat->error($e); $this->error($response, $e, HttpConstants::STATUS_INTERNAL_SERVER_ERROR, false); } } catch (\lang\Throwable $e) { $cat->error($e); // Here, we might not have a scriptlet instance; and thus not a response if (!isset($response)) { $response = isset($instance) ? $instance->response() : new HttpScriptletResponse(); } $this->error($response, $e, HttpConstants::STATUS_PRECONDITION_FAILED, $flags & WebDebug::STACKTRACE); } // Send output $response->isCommitted() || $response->flush(); $response->sendContent(); // Call scriptlet's finalizer $instance && $instance->finalize(); // Debugging if ($flags & WebDebug::XML && isset($response->document)) { flush(); echo '<xmp>', $response->document->getDeclaration() . "\n" . $response->document->getSource(0), '</xmp>'; } if ($flags & WebDebug::ERRORS) { flush(); echo '<xmp>', $e ? $e->toString() : '', \xp::stringOf(\xp::$errors), '</xmp>'; } }
/** * Handle POST requests. The POST data carries the XML-RPC * request. * * @param scriptlet.rpc.AbstractRpcRequest $request * @param scriptlet.rpc.AbstractRpcResponse $response */ public function doPost($request, $response) { $this->cat && $response->setTrace($this->cat); $this->cat && $request->setTrace($this->cat); $hasFault = false; $answer = $this->_message(); try { // Get message $msg = $request->getMessage(); // Create answer $answer->create($msg); // Call handler $return = $this->callReflectHandler($msg); } catch (\lang\reflect\TargetInvocationException $e) { $hasFault = true; // Log exception Logger::getInstance()->getCategory(nameof($this))->error(nameof($this), '~ invocation returned exception', $e); $cause = $e->getCause(); if ($cause instanceof ServiceException) { // Server methods may throw a ServiceException to have more // convenient control over the faultcode which is returned to the client. $answer->setFault($cause->getFaultcode(), $cause->getMessage(), $request->getEnvValue('SERVER_NAME') . ':' . $request->getEnvValue('SERVER_PORT'), $this->formatStackTrace($cause->getStackTrace())); } else { $answer->setFault(\peer\http\HttpConstants::STATUS_INTERNAL_SERVER_ERROR, $cause->getMessage(), $request->getEnvValue('SERVER_NAME') . ':' . $request->getEnvValue('SERVER_PORT'), $this->formatStackTrace($cause->getStackTrace())); } } catch (\lang\XPException $e) { // Log exception Logger::getInstance()->getCategory(nameof($this))->error(nameof($this), '~ invocation returned exception', $e); $answer->setFault(\peer\http\HttpConstants::STATUS_INTERNAL_SERVER_ERROR, $e->getMessage(), $request->getEnvValue('SERVER_NAME') . ':' . $request->getEnvValue('SERVER_PORT'), $this->formatStackTrace($e->getStackTrace())); $hasFault = true; } $hasFault || $answer->setData($return); // Set message $response->setHeader('Content-type', $answer->getContentType() . '; charset=' . $answer->getEncoding()); $response->setMessage($answer); }
/** * Runs class * * @param string $command * @param util.cmd.ParamString $params * @param util.cmd.Config $config * @return int */ protected function runCommand($command, $params, $config) { try { $class = Commands::named($command); } catch (Throwable $e) { self::$err->writeLine('*** ', $this->verbose ? $e : $e->getMessage()); return 1; } // Usage if ($params->exists('help', '?')) { $this->commandUsage($class); return 0; } // BC: PropertyManager, Logger, ConnectionManager instances $pm = PropertyManager::getInstance(); $pm->setSources($config->sources()); $l = Logger::getInstance(); $pm->hasProperties('log') && $l->configure($pm->getProperties('log')); if (class_exists('rdbms\\DBConnection')) { // FIXME: Job of XPInjector? $cm = ConnectionManager::getInstance(); $pm->hasProperties('database') && $cm->configure($pm->getProperties('database')); } // Setup logger context for all registered log categories foreach (Logger::getInstance()->getCategories() as $category) { if (null === ($context = $category->getContext()) || !$context instanceof EnvironmentAware) { continue; } $context->setHostname(System::getProperty('host.name')); $context->setRunner(nameof($this)); $context->setInstance($class->getName()); $context->setResource(null); $context->setParams($params->string); } if ($class->hasMethod('newInstance')) { $instance = $class->getMethod('newInstance')->invoke(null, [$config]); } else { if ($class->hasConstructor()) { $instance = $class->newInstance($config); } else { $instance = $class->newInstance(); } } $instance->in = self::$in; $instance->out = self::$out; $instance->err = self::$err; $methods = $class->getMethods(); // Injection foreach ($methods as $method) { if (!$method->hasAnnotation('inject')) { continue; } $inject = $method->getAnnotation('inject'); if (isset($inject['type'])) { $type = $inject['type']; } else { if ($restriction = $method->getParameter(0)->getTypeRestriction()) { $type = $restriction->getName(); } else { $type = $method->getParameter(0)->getType()->getName(); } } try { switch ($type) { case 'rdbms.DBConnection': $args = [$cm->getByHost($inject['name'], 0)]; break; case 'util.Properties': $p = $pm->getProperties($inject['name']); // If a PropertyAccess is retrieved which is not a util.Properties, // then, for BC sake, convert it into a util.Properties if ($p instanceof PropertyAccess && !$p instanceof Properties) { $convert = new Properties(null); $convert->load(new \io\streams\MemoryInputStream('')); $section = $p->getFirstSection(); while ($section) { // HACK: Properties::writeSection() would first attempts to // read the whole file, we cannot make use of it. $convert->_data[$section] = $p->readSection($section); $section = $p->getNextSection(); } $args = [$convert]; } else { $args = [$p]; } break; case 'util.log.LogCategory': $args = [$l->getCategory($inject['name'])]; break; default: self::$err->writeLine('*** Unknown injection type "' . $type . '" at method "' . $method->getName() . '"'); return 2; } $method->invoke($instance, $args); } catch (TargetInvocationException $e) { self::$err->writeLine('*** Error injecting ' . $type . ' ' . $inject['name'] . ': ' . $e->getCause()->compoundMessage()); return 2; } catch (Throwable $e) { self::$err->writeLine('*** Error injecting ' . $type . ' ' . $inject['name'] . ': ' . $e->compoundMessage()); return 2; } } // Arguments foreach ($methods as $method) { if ($method->hasAnnotation('args')) { // Pass all arguments if (!$method->hasAnnotation('args', 'select')) { $begin = 0; $end = $params->count; $pass = array_slice($params->list, 0, $end); } else { $pass = []; foreach (preg_split('/, ?/', $method->getAnnotation('args', 'select')) as $def) { if (is_numeric($def) || '-' == $def[0]) { $pass[] = $params->value((int) $def); } else { sscanf($def, '[%d..%d]', $begin, $end); isset($begin) || ($begin = 0); isset($end) || ($end = $params->count - 1); while ($begin <= $end) { $pass[] = $params->value($begin++); } } } } try { $method->invoke($instance, [$pass]); } catch (Throwable $e) { self::$err->writeLine('*** Error for arguments ' . $begin . '..' . $end . ': ', $this->verbose ? $e : $e->getMessage()); return 2; } } else { if ($method->hasAnnotation('arg')) { // Pass arguments $arg = $method->getAnnotation('arg'); if (isset($arg['position'])) { $name = '#' . ($arg['position'] + 1); $select = intval($arg['position']); $short = null; } else { if (isset($arg['name'])) { $name = $select = $arg['name']; $short = isset($arg['short']) ? $arg['short'] : null; } else { $name = $select = strtolower(preg_replace('/^set/', '', $method->getName())); $short = isset($arg['short']) ? $arg['short'] : null; } } if (0 == $method->numParameters()) { if (!$params->exists($select, $short)) { continue; } $args = []; } else { if (!$params->exists($select, $short)) { list($first, ) = $method->getParameters(); if (!$first->isOptional()) { self::$err->writeLine('*** Argument ' . $name . ' does not exist!'); return 2; } $args = []; } else { $args = [$params->value($select, $short)]; } } try { $method->invoke($instance, $args); } catch (TargetInvocationException $e) { self::$err->writeLine('*** Error for argument ' . $name . ': ', $this->verbose ? $e->getCause() : $e->getCause()->compoundMessage()); return 2; } } } } try { return (int) $instance->run(); } catch (Throwable $t) { self::$err->writeLine('*** ', $t->toString()); return 70; // EX_SOFTWARE according to sysexits.h } }
public function notFoundExceptionLevelConfigure() { $cat = Logger::getInstance()->getCategory('scriptlet'); $appender = $cat->addAppender(new BufferedAppender()); $this->runWith('dev', '/notfounderror'); $buffer = $appender->getBuffer(); $this->assertContained('error] Exception', $buffer); $this->runWith('dev', '/notfoundwarn'); $buffer = $appender->getBuffer(); $this->assertContained('warn] Exception', $buffer); $cat->removeAppender($appender); }
public function errorPageLoggingInDevMode() { with($cat = \util\log\Logger::getInstance()->getCategory('scriptlet')); $appender = $cat->addAppender(new BufferedAppender()); $this->runWith('dev', '/error'); $buffer = $appender->getBuffer(); $cat->removeAppender($appender); $this->assertContained('Injected util.log.LogCategory', $buffer); $this->assertContained('Exception scriptlet.ScriptletException (500:Request processing failed [doGet]: No shoes, no shorts, no service)', $buffer); }
/** * Constructor. * * @param string argument */ public function __construct($arg) { $this->cat = Logger::getInstance()->getCategory($arg); }
public function named_logcategory_injection() { $class = \lang\ClassLoader::defineClass('AbstractRestRouterTest_NamedLogcategoryInjection', 'lang.Object', [], '{ public $cat; #[@inject(type = "util.log.LogCategory", name = "test")] public function setTrace($cat) { $this->cat= $cat; } }'); $cat = Logger::getInstance()->getCategory('test'); $this->assertEquals($cat, $this->fixture->handlerInstanceFor($class)->cat); }
/** * Returns arguments used for injection * * @param lang.reflect.Routine routine * @return var[] args */ protected function injectionArgs($routine) { if ($routine->numParameters() < 1) { return []; } $inject = $routine->getAnnotation('inject'); $type = isset($inject['type']) ? $inject['type'] : $routine->getParameter(0)->getType()->getName(); switch ($type) { case 'util.log.LogCategory': $args = [isset($inject['name']) ? Logger::getInstance()->getCategory($inject['name']) : $this->cat]; break; case 'util.Properties': $args = [PropertyManager::getInstance()->getProperties($inject['name'])]; break; case 'webservices.rest.srv.RestContext': $args = [$this]; break; default: throw new IllegalStateException('Unkown injection type ' . $type); } return $args; }