{"comment":{"created_at":"2011-10-17T15:55:25Z","body":"Reset to draft - this needs some more thought\n\n\n\nfriebe, Wed, 10 Oct 2007 21:46:14 +0200","updated_at":"2011-10-17T15:55:25Z","url":"https://api.github.com/repos/xp-framework/rfc/issues/comments/2430679","id":2430679,"user":{"gravatar_id":"26f07e3b262e9a80436f368cb11bd0c2","avatar_url":"https://secure.gravatar.com/avatar/26f07e3b262e9a80436f368cb11bd0c2?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/thekid","id":696742,"login":"thekid"}},"action":"created","issue":{"number":109,"created_at":"2011-10-17T15:54:39Z","pull_request":{"diff_url":null,"patch_url":null,"html_url":null},"body":"Scope of Change\n====\nA new package invoke will be added.\n\n\nRationale\n====\nMethod invocation utilities.\n\n\nFunctionality\n====\n\nInvocation chain\n----\nExample: Prerequisites-check:\n\n```php\n<?php\n  class Account extends Object {\n  \n    public function transfer($amount) {\n      // TBI\n    }\n  }\n\n  class SecurityInterceptor extends Object implements InvocationInterceptor {\n    protected $level;\n\n    public function __construct($level) {\n      $this->level= $level;\n    }\n  \n    public function invoke(InvocationChain $chain) {\n      if (\n        'transfer' == $chain->method->getName() && \n        $chain->parameters[0] > 10000 &&\n        $this->level < 4\n      ) {\n        throw new IllegalAccessException(sprintf(\n          'Clearance level IV needed to transfer %d EUR', \n          $chain->parameters[0]\n        );\n        \n        return $chain->proceed();\n      }\n    }\n  }\n\n  $account= new Account();\n  \n  // Use invocation chain to invoke transfer() instead of calling it directly\n  $chain= new InvocationChain();\n  $chain->addInterceptor(new SecurityInterceptor(3));\n  \n  // Will throw an exception because of unmet prerequisites\n  $result= $chain->invoke(\n    $account, \n    $account->getClass()->getMethod('transfer'), \n    array(120000)\n  );\n?>\n```\n\nExample: Logging:\n\n```php\n<?php\n  class LoggingInterceptor extends Object implements InvocationInterceptor {\n    protected $cat;\n\n    public function __construct($cat) {\n      $this->cat= $cat;\n    }\n  \n    public function invoke(InvocationChain $chain) {\n      $this->cat->debug('Invoking', $chain->method, '(', $chain->parameters, ')');\n      try {\n        $result= $chain->proceed();\n      } catch (Throwable $e) {\n        $this->cat->warn($e);\n        throw $e;\n      }\n      $this->cat->info('Result', $result);\n      return $result;\n    }\n  }\n?>\n```\n\n\nLazy initialization\n----\nThe util.AbstractDeferredInvokationHandler class will be moved to invoke\nand be renamed to AbstractDeferredInvocationHandler (invocation is spelled with\na \"c\", while invoke is spelled with a \"k\").\n\n\nCaller\n----\nFinding out a method's caller:\n\n\n```php\n<?php\n  class Account extends Object {\n  \n    public function deposit($amount) {\n      $this->cat->debug('Called from', InvocationContext::getCaller());\n\n      // TBI\n    }\n\n    public function withdraw($amount) {\n      $this->cat->debug('Called from', InvocationContext::getCaller());\n\n      // TBI\n    }\n  }\n  \n  class MonetaryTransaction extends Object {\n  \n    public function transfer(Account $origin, Account $destination, $amount) {\n      $origin->withdraw($amount);\n      $destination->deposit($amount);\n    }\n  }\n  \n  $t= new MonetaryTransaction();\n  $t->transfer(Account::getByAccountNumber(1), Account::getByAccountNumber(2), 100);\n?>\n```\n\nThis will print somthing like:\n\n```\n  [15:55:19 29540 debug] Called from invoke.Invocation@{\n    [instance  ] com.example.banking.MonetaryTransaction{}\n    [class     ] lang.XPClass<com.example.banking.MonetaryTransaction>\n    [method    ] public transfer($origin, $destination, $amount)\n    [arguments ] [\n      0 => com.example.banking.Account<#1>\n      1 => com.example.banking.Account<#2>\n      2 => 100\n    ]\n  }\n\n```\n\nAnother example of using the invocation class:\n\n```php\n<?php\n  $repr= $instance->getClass()->getMethod('toString')->invoke($instance);\n\n  $i= new Invocation($instance, 'toString');\n  $repr= $i->invoke();  \n?>\n```\n\n\nInvocation comparison\n----\nInstead of manually comparing class name, method and parameter counts in\ninterceptors, one can make use of the PointCutExpression class.\n\n```php\n<?php\n  if (\n    'com.example.banking.Account' == $chain->instance->getClassName() &&\n    'transfer' == $chain->method->getName() && \n    1 == sizeof($chain->parameters) &&\n    $chain->parameters[0] > 10000 &&\n    $this->level < 4\n  ) {\n    // ...\n  }\n  \n  $pc= new PointCutExpression('call:com.example.banking.Account::transfer(1)');\n  if (\n    $pc->matches($chain->invocation()) && \n    $chain->parameters[0] > 10000 && \n    $this->level < 4\n  ) {\n    // ...\n  }\n?>\n```\n\nSyntax that can be used in forName():\n\n```\n  call:[class]::[method]([narguments])\n  new:[class]([narguments])\n\n```\n\nWhere:\n- \"class\" is the fully qualified class name\n\n- \"method\" name is the method name or the '*' (for any method)\n\n- \"narguments\" is either a number of arguments or the '*' \n  (for any given number of parameters)\n\n\nSecurity considerations\n====\nn/a\n\n\nSpeed impact\n====\nn/a\n\n\nDependencies\n====\nn/a\n\n\nRelated documents\n====\n- http://www.google.com/search?q=InvocationChain\n  Other InvocationChain implementations\n\n- xp-framework/rfc #29: util.AbstractDeferredInvokationHandler\n  This will be deprecated and moved to invoke\n\n- http://javaspecialists.co.za/archive/newsletter.do?issue=005&locale=en_US\n  Dynamic Proxies - Short Tutorial\n\n- http://video.google.com/videoplay?docid=8566923311315412414\n  Aspect Oriented Programming\n\n- http://javaspecialists.co.za/archive/newsletter.do?issue=087&locale=en_US\n  sun.reflect.Reflection\n\n","comments":1,"title":"Invocation utilities package","updated_at":"2011-10-17T15:55:26Z","url":"https://api.github.com/repos/xp-framework/rfc/issues/109","id":1930182,"assignee":null,"milestone":{"number":60,"created_at":"2011-10-17T15:55:10Z","due_on":null,"title":"5.9-Series","creator":{"gravatar_id":"66552a028d39afd16f21858d7ac9cf41","avatar_url":"https://secure.gravatar.com/avatar/66552a028d39afd16f21858d7ac9cf41?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/kiesel","id":127769,"login":"kiesel"},"url":"https://api.github.com/repos/xp-framework/rfc/milestones/60","open_issues":1,"closed_issues":0,"description":"","state":"open"},"closed_at":null,"user":{"gravatar_id":"26f07e3b262e9a80436f368cb11bd0c2","avatar_url":"https://secure.gravatar.com/avatar/26f07e3b262e9a80436f368cb11bd0c2?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/thekid","id":696742,"login":"thekid"},"html_url":"https://github.com/xp-framework/rfc/issues/109","labels":[{"name":"draft","url":"https://api.github.com/repos/xp-framework/rfc/labels/draft","color":"7890d4"},{"name":"framework","url":"https://api.github.com/repos/xp-framework/rfc/labels/framework","color":"118f5b"}],"state":"open"},"legacy":{"issue_id":1930182,"comment_id":2430679}}