Example #1
0
 /**
  * Registers aspects written within source files which we might encounter
  *
  * @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance
  *
  * @return void
  */
 public function registerAspectXml(ApplicationInterface $application)
 {
     /** @var \AppserverIo\Appserver\Core\Api\ConfigurationService $configurationService */
     $configurationService = $application->newService('AppserverIo\\Appserver\\Core\\Api\\ConfigurationService');
     // check if we even have a XMl file to read from
     $xmlPaths = $configurationService->globDir($this->getWebappPath() . DIRECTORY_SEPARATOR . '{WEB-INF,META-INF,common}' . DIRECTORY_SEPARATOR . self::CONFIG_FILE, GLOB_BRACE);
     foreach ($xmlPaths as $xmlPath) {
         // iterate all XML configuration files we found
         if (is_readable($xmlPath)) {
             // validate the file here, if it is not valid we can skip further steps
             try {
                 $configurationService->validateFile($xmlPath, null, true);
             } catch (InvalidConfigurationException $e) {
                 /** @var \Psr\Log\LoggerInterface $systemLogger */
                 $systemLogger = $this->getApplication()->getInitialContext()->getSystemLogger();
                 $systemLogger->error($e->getMessage());
                 $systemLogger->critical(sprintf('Pointcuts configuration file %s is invalid, AOP functionality might not work as expected.', $xmlPath));
                 continue;
             }
             // load the aop config
             $config = new \SimpleXMLElement(file_get_contents($xmlPath));
             $config->registerXPathNamespace('a', 'http://www.appserver.io/appserver');
             // create us an aspect
             // name of the aspect will be the application name
             $aspect = new Aspect();
             $aspect->setName($xmlPath);
             // check if we got some pointcuts
             foreach ($config->xpath('/a:pointcuts/a:pointcut') as $pointcutConfiguration) {
                 // build up the pointcut and add it to the collection
                 $pointcut = new Pointcut();
                 $pointcut->setAspectName($aspect->getName());
                 $pointcut->setName((string) $pointcutConfiguration->{'pointcut-name'});
                 $pointcut->setPointcutExpression(new PointcutExpression((string) $pointcutConfiguration->{'pointcut-pattern'}));
                 $aspect->getPointcuts()->add($pointcut);
             }
             // check if we got some advices
             foreach ($config->xpath('/a:pointcuts/a:advice') as $adviceConfiguration) {
                 // build up the advice and add it to the aspect
                 $advice = new Advice();
                 $advice->setAspectName((string) $adviceConfiguration->{'advice-aspect'});
                 $advice->setName($advice->getAspectName() . '->' . (string) $adviceConfiguration->{'advice-name'});
                 $advice->setCodeHook((string) $adviceConfiguration->{'advice-type'});
                 $pointcutPointcut = $this->generatePointcutPointcut((array) $adviceConfiguration->{'advice-pointcuts'}->{'pointcut-name'}, $aspect);
                 $advice->getPointcuts()->add($pointcutPointcut);
                 // finally add the advice to our aspect (we will also add it without pointcuts of its own)
                 $aspect->getAdvices()->add($advice);
             }
             // if the aspect contains pointcuts or advices it can be used
             if ($aspect->getPointcuts()->count() > 0 || $aspect->getAdvices()->count() > 0) {
                 $this->getAspectRegister()->set($aspect->getName(), $aspect);
             }
         }
     }
 }
 /**
  * Will register a complete aspect to the AspectRegister.
  * This include its advices and pointcuts which can be looked up from this point on
  *
  * @param \AppserverIo\Doppelgaenger\Entities\Definitions\AspectDefinition $aspectDefinition Structure to register as an aspect
  *
  * @return null
  */
 public function register(AspectDefinition $aspectDefinition)
 {
     // create the new aspect and fill it with things we already know
     $aspect = new Aspect();
     $aspect->setName($aspectDefinition->getName());
     $aspect->setNamespace($aspectDefinition->getNamespace());
     // prepare the tokenizer we will need for further processing
     $needles = array(AfterReturning::ANNOTATION, AfterThrowing::ANNOTATION, After::ANNOTATION, Around::ANNOTATION, Before::ANNOTATION);
     $tokenizer = new Tokenizer();
     $tokenizer->ignore(array('param', 'return', 'throws'));
     // iterate the functions and filter out the ones used as advices
     $scheduledAdviceDefinitions = array();
     foreach ($aspectDefinition->getFunctionDefinitions() as $functionDefinition) {
         $foundNeedle = false;
         foreach ($needles as $needle) {
             // create the advice
             if (strpos($functionDefinition->getDocBlock(), '@' . $needle) !== false) {
                 $foundNeedle = true;
                 $scheduledAdviceDefinitions[$needle][] = $functionDefinition;
                 break;
             }
         }
         // create the pointcut
         if (!$foundNeedle && strpos($functionDefinition->getDocBlock(), '@' . Pointcut::ANNOTATION) !== false) {
             $pointcut = new PointcutDefinition();
             $pointcut->setName($functionDefinition->getName());
             $tokens = new Tokens($tokenizer->parse($functionDefinition->getDocBlock()));
             // convert to array and run it through our advice factory
             $toArray = new ToArray();
             $annotations = $toArray->convert($tokens);
             // create the entities for the join-points and advices the pointcut describes
             $pointcut->setPointcutExpression(new PointcutExpression(array_pop(array_pop($annotations)->values)));
             $aspect->getPointcuts()->add($pointcut);
         }
     }
     $this->add($aspect);
     // do the pointcut lookups where we will need the pointcut factory for later use
     $pointcutFactory = new PointcutFactory();
     foreach ($scheduledAdviceDefinitions as $codeHook => $hookedAdviceDefinitions) {
         foreach ($hookedAdviceDefinitions as $scheduledAdviceDefinition) {
             // create our advice
             $advice = new Advice();
             $advice->setAspectName($aspectDefinition->getQualifiedName());
             $advice->setName($scheduledAdviceDefinition->getName());
             $advice->setCodeHook((string) $codeHook);
             $tokens = new Tokens($tokenizer->parse($scheduledAdviceDefinition->getDocBlock()));
             // convert to array and run it through our advice factory
             $toArray = new ToArray();
             $annotations = $toArray->convert($tokens);
             // create the entities for the join-points and advices the pointcut describes
             foreach ($annotations as $annotation) {
                 $pointcut = $pointcutFactory->getInstance(array_pop($annotation->values));
                 if ($pointcut instanceof PointcutPointcut) {
                     // get the referenced pointcuts for the split parts of the expression
                     $expressionParts = explode(PointcutPointcut::EXPRESSION_CONNECTOR, $pointcut->getExpression());
                     // lookup all the referenced pointcuts
                     $referencedPointcuts = array();
                     foreach ($expressionParts as $expressionPart) {
                         $referencedPointcuts = array_merge($referencedPointcuts, $this->lookupPointcuts($expressionPart));
                     }
                     $pointcut->setReferencedPointcuts($referencedPointcuts);
                 }
                 $advice->getPointcuts()->add($pointcut);
             }
             $aspect->getAdvices()->add($advice);
         }
     }
     $this->set($aspectDefinition->getQualifiedName(), $aspect);
 }