00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00021 class PEIP_XML_Context
00022 implements
00023 PEIP_INF_Context,
00024 PEIP_INF_Channel_Resolver {
00025
00026 protected
00027 $services = array(),
00028 $configs = array(),
00029 $gateways = array(),
00030 $nodeBuilders = array(),
00031 $channelRegistry;
00032
00033
00034
00035
00041 public function __construct($xml){
00042 $this->simpleXML = new SimpleXMLIterator($xml);
00043 $this->initNodeBuilders();
00044 $this->init();
00045 }
00046
00047 public static function createFromString($xml){
00048 return new PEIP_XML_Context($xml);
00049 }
00050
00051 public static function createFromFile($file){
00052 if(file_exists($file)){
00053 return self::createFromString(file_get_contents($file));
00054 }else{
00055 throw new RuntimeException('Cannot open file "'.$file.'".');
00056 }
00057 }
00058
00059
00066 public function registerNodeBuilder($nodeName, $callable){
00067 $this->nodeBuilders[$nodeName] = $callable;
00068 }
00069
00070
00076 public function addPlugin(PEIP_INF_Context_Plugin $plugin){
00077 $plugin->init($this);
00078 }
00079
00080
00086 public function createPlugin($config){
00087 $plugin = $this->createService($config);
00088 $this->addPlugin($plugin);
00089 }
00090
00091
00092 private function initNodeBuilders(){
00093 $builders = array(
00094 'plugin' => 'createPlugin',
00095 'channel' => 'createChannel',
00096 'publish_subscribe_channel' => 'createSubscribebalChannel',
00097 'service' => 'initService',
00098 'service_activator' => 'createServiceActivator',
00099 'gateway' => 'createGateway',
00100 'splitter' => 'createSplitter',
00101 'router' => 'createRouter',
00102 'aggregator' => 'createAggregator',
00103 'wiretap' => 'createWiretap'
00104
00105 );
00106 foreach($builders as $nodeName => $method){
00107 $this->registerNodeBuilder($nodeName, array($this, $method));
00108 }
00109 }
00110
00111
00125 protected function buildNode($node){
00126 $nodeName = $node->getName();
00127 if(array_key_exists($nodeName, $this->nodeBuilders)){
00128 call_user_func($this->nodeBuilders[$nodeName], $node);
00129 }
00130 }
00131
00132
00137 protected function init(){
00138 $xml = $this->simpleXML;
00139 $this->channelRegistry = PEIP_Channel_Registry::getInstance();
00140 if($xml['id']){
00141 $this->services[(string)$xml['id']] = $this;
00142 }
00143 foreach($xml->children() as $entry){
00144 $this->buildNode($entry);
00145 }
00146 }
00147
00148
00154 public function resolveChannelName($channelName){
00155 return $this->channelRegistry->get($channelName);
00156 }
00157
00158
00164 public function getService($id){
00165 return $this->hasService($id)
00166 ? $this->services[$id]
00167 : NULL;
00168 }
00169
00170
00176 public function hasService($id){
00177 return isset($this->services[$id]);
00178 }
00179
00180
00186 protected function requestService($id){
00187 $service = $this->getService($id);
00188 if($service === NULL){
00189 throw new RuntimeException('Service "'.$id.'" not found.');
00190 }
00191 return $service;
00192 }
00193
00194
00205 protected function initService($config){
00206 $id = trim((string)$config['id']);
00207 if($id != ''){
00208 return $this->services[$id] = $this->createService($config);
00209 }
00210 }
00211
00212
00213
00219 public function createService($config){
00220 $args = array();
00221 if($config->constructor_arg){
00222 foreach($config->constructor_arg as $arg){
00223 $args[] = $this->buildArg($arg);
00224 }
00225 }
00226 return $this->buildAndModify($config, $args);
00227 }
00228
00229
00236 protected function modifyService($service, $config){
00237 if($config->property){
00238 foreach($config->property as $property){
00239 $setter = self::getSetter($property);
00240 if($setter){
00241 $arg = $this->buildArg($property);
00242 if($arg){
00243 $service->{$setter}($arg);
00244 }
00245 }
00246 }
00247 }
00248 if($config->action){
00249 foreach($config->action as $action){
00250 if($action['method'] && method_exists($service, (string)$action['method'])){
00251 $args = array();
00252 foreach($action->children() as $argument){
00253 $args[] = $this->buildArg($argument);
00254 }
00255 call_user_func_array(array($service, (string)$action['method']), $args);
00256 }
00257 }
00258 }
00259 if($service instanceof PEIP_INF_Connectable){
00260 if($config->listener){
00261 foreach($config->listener as $listenerConf){
00262 $event = (string)$listenerConf['event'];
00263 $listener = $this->provideService($config);
00264 $service->connect($event, $listener);
00265 }
00266 }
00267 }
00268 return $service;
00269 }
00270
00271
00277 public function getGateway($id){
00278 return $this->gateways[$id];
00279 }
00280
00281
00287 public function createChannel($config){
00288 return $this->doCreateChannel($config, 'PEIP_Pollable_Channel');
00289 }
00290
00291
00297 public function createSubscribebalChannel($config){
00298 return $this->doCreateChannel($config, 'PEIP_Publish_Subscribe_Channel');
00299 }
00300
00301
00309 public function doCreateChannel($config, $defaultChannel, array $additionalArguments = array()){
00310 $id = (string)$config['id'];
00311 if($id != ''){
00312 array_unshift($additionalArguments, $id);
00313 $channel = $this->buildAndModify($config, array($id), $defaultChannel);
00314 $this->channelRegistry->register($channel);
00315 return $channel;
00316 }
00317 }
00318
00319
00320
00327 public function createGateway($config, $defaultClass = false){
00328 $args = array(
00329 $this->getRequestChannel($config),
00330 $this->getReplyChannel($config)
00331 );
00332 $defaultClass = $defaultClass ? $defaultClass : 'PEIP_Simple_Messaging_Gateway';
00333 $gateway = $this->buildAndModify($config, $args, $defaultClass);
00334 $id = (string)$config["id"];
00335 $this->gateways[$id] = $gateway;
00336 return $gateway;
00337 }
00338
00339
00345 public function createRouter($config){
00346 $resolver = $config['channel_resolver'] ? (string)$config['channel_resolver'] : $this->channelRegistry;
00347 return $this->buildAndModify($config, array(
00348 $resolver,
00349 $this->doGetChannel('input', $config)
00350 ));
00351 }
00352
00353
00359 public function createSplitter($config){
00360 return $this->createReplyMessageHandler($config);
00361 }
00362
00363
00369 public function createAggregator($config){
00370 return $this->createReplyMessageHandler($config);
00371 }
00372
00373
00379 public function createWiretap($config){
00380 return $this->createReplyMessageHandler($config, 'PEIP_Wiretap');
00381 }
00382
00383
00390 public function createReplyMessageHandler($config, $defaultClass = false){
00391 return $this->buildAndModify($config, $this->getReplyHandlerArguments($config), $defaultClass);
00392 }
00393
00394
00395
00408 public function createServiceActivator($config, $defaultClass = false){
00409 $method = (string)$config['method'];
00410 $service = $this->getService((string)$config['ref']);
00411 if($method && $service){
00412 $args = $this->getReplyHandlerArguments($config);
00413 array_unshift($args,array(
00414 $service,
00415 $method
00416 ));
00417 echo $defaultClass = $defaultClass ? $defaultClass : 'PEIP_Service_Activator';
00418 return $this->buildAndModify($config, $args, $defaultClass);
00419 }
00420 }
00421
00422
00428 protected function provideService($config){
00429 $ref = trim((string)$config['ref']);
00430 if($ref != ''){
00431 $service = $this->getService($ref);
00432 }else{
00433 $service = $this->createService($config);
00434 }
00435 return $service;
00436 }
00437
00438 protected static function getSetter($config){
00439 if($config['setter']){
00440 $setter = (string)$config['setter'];
00441 }elseif($config['name']){
00442 $setter = 'set'.ucfirst((string)$config['name']);
00443 }
00444 return $setter;
00445 }
00446
00447
00448
00449
00463 protected function buildArg($config){
00464 if(trim((string)$config['value']) != ''){
00465 $arg = (string)$config['value'];
00466 }elseif($config->getName() == 'value'){
00467 $arg = (string)$config;
00468 }elseif($config->getName() == 'list'){
00469 $arg = array();
00470 foreach($config->children() as $entry){
00471 if($entry->getName() == 'value'){
00472 if($entry['key']){
00473 $arg[(string)$entry['key']] = (string)$entry;
00474 }else{
00475 $arg[] = (string)$entry;
00476 }
00477 }elseif($entry->getName() == 'service'){
00478 $arg[] = $this->provideService($entry);
00479 }
00480 }
00481 }elseif($config->getName() == 'service'){
00482 $arg = $this->provideService($config);
00483 }elseif($config->list){
00484 $arg = $this->buildArg($config->list);
00485 }elseif($config->service){
00486 $arg = $this->buildArg($config->service);
00487 }
00488 return $arg;
00489 }
00490
00491
00497 protected function getReplyHandlerArguments($config){
00498 $args = array(
00499 $this->doGetChannel('input', $config),
00500 $this->doGetChannel('output', $config)
00501 );
00502 if($args[0] == NULL){
00503 throw new RuntimeException('Could not receive input channel.');
00504 }
00505 return $args;
00506 }
00507
00508
00514 protected function getRequestChannel($config){
00515 return $this->doGetChannel('request', $config);
00516 }
00517
00518
00524 protected function getReplyChannel($config){
00525 return $this->doGetChannel('reply', $config);
00526 }
00527
00528
00535 public function doGetChannel($type, $config){
00536 $channelName = $config[$type."_channel"]
00537 ? $config[$type."_channel"]
00538 : $config["default_".$type."_channel"];
00539 $channel = $this->services[trim((string)$channelName)];
00540 if($channel instanceof PEIP_INF_Channel){
00541 return $channel;
00542 }else{
00543 return NULL;
00544 }
00545 }
00546
00547
00555 public function buildAndModify($config, $arguments, $defaultClass = false){
00556 $service = $this->modifyService(self::doBuild($config, $arguments, $defaultClass), $config);
00557 $id = trim((string)$config['id']);
00558 if($service && $id != ''){
00559 $this->services[$id] = $service;
00560 }
00561 return $service;
00562 }
00563
00564 protected static function doBuild($config, $arguments, $defaultClass = false){
00565 $cls = $config["class"] ? trim((string)$config["class"]) : (string)$defaultClass;
00566 if($cls != ''){
00567 try {
00568 return self::build($cls, $arguments);
00569 }catch(Exception $e){
00570 throw new RuntimeException('Could not create Service "'.$cls.'" -> '.$e->getMessage());
00571 }
00572 }
00573 throw new RuntimeException('Could not create Service "'.$cls.'". Class does not exist.');
00574 }
00575
00576 protected static function build($className, $arguments){
00577 return PEIP_Generic_Builder::getInstance($className)->build($arguments);
00578 }
00579
00580
00581 }