/**
  * 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;
     }
 }
Example #5
0
 /**
  * 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("  [%s %d %.3fkB] %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("@", $this, "");
     Console::writeLine("Serving ", $layout);
     Console::writeLine("", str_repeat('═', 72), "");
     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("> Server started: ", $this->url, " (", 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>';
     }
 }
Example #9
0
 /**
  * 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;
 }
Example #10
0
 public function setDebug($d = FALSE)
 {
     if (NULL === $d) {
         Logger::getInstance()->getCategory()->withAppender(new ColoredConsoleAppender());
     }
 }
Example #11
0
 /**
  * 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);
 }
Example #18
0
 /**
  * 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;
 }