/**
  * Will generate the structure map within the specified root path.
  *
  * @return void
  */
 protected function generate()
 {
     // first of all we will get the version, so we will later know about changes made DURING indexing
     $this->version = $this->findVersion();
     // get the iterator over our project files and create a regex iterator to filter what we got
     $recursiveIterator = $this->getProjectIterator();
     $regexIterator = new \RegexIterator($recursiveIterator, '/^.+\\.php$/i', \RecursiveRegexIterator::GET_MATCH);
     // get the list of enforced files
     $enforcedFiles = $this->getEnforcedFiles();
     // if we got namespaces which are omitted from enforcement we have to mark them as such
     $omittedNamespaces = array();
     if ($this->config->hasValue('enforcement/omit')) {
         $omittedNamespaces = $this->config->getValue('enforcement/omit');
     }
     // iterator over our project files and add array based structure representations
     foreach ($regexIterator as $file) {
         // get the identifiers if any.
         $identifier = $this->findIdentifier($file[0]);
         // if we got an identifier we can build up a new map entry
         if ($identifier !== false) {
             // We need to get our array of needles
             $needles = array(Invariant::ANNOTATION, Ensures::ANNOTATION, Requires::ANNOTATION, After::ANNOTATION, AfterReturning::ANNOTATION, AfterThrowing::ANNOTATION, Around::ANNOTATION, Before::ANNOTATION, Introduce::ANNOTATION, Pointcut::ANNOTATION);
             // If we have to enforce things like @param or @returns, we have to be more sensitive
             if ($this->config->getValue('enforcement/enforce-default-type-safety') === true) {
                 $needles[] = '@var';
                 $needles[] = '@param';
                 $needles[] = '@return';
             }
             // check if the file has contracts and if it should be enforced
             $hasAnnotations = $this->findAnnotations($file[0], $needles);
             // create the entry
             $this->map[$identifier[1]] = array('cTime' => filectime($file[0]), 'identifier' => $identifier[1], 'path' => $file[0], 'type' => $identifier[0], 'hasAnnotations' => $hasAnnotations, 'enforced' => $this->isFileEnforced($file[0], $identifier[1], $hasAnnotations, $enforcedFiles, $omittedNamespaces));
         }
     }
     // save for later reuse.
     $this->save();
 }
 /**
  * Will load any given structure based on it's availability in our structure map which depends on the configured
  * project directories.
  * If the structure cannot be found we will redirect to the composer autoloader which we registered as a fallback
  *
  * @param string $className The name of the structure we will try to load
  *
  * @return boolean
  */
 public function loadClass($className)
 {
     // Might the class be a omitted one? If so we can require the original.
     if ($this->config->hasValue('autoloader/omit')) {
         $omittedNamespaces = $this->config->getValue('autoloader/omit');
         foreach ($omittedNamespaces as $omitted) {
             // If our class name begins with the omitted part e.g. it's namespace
             if (strpos($className, str_replace('\\\\', '\\', $omitted)) === 0) {
                 return false;
             }
         }
     }
     // Do we have the file in our cache dir? If we are in development mode we have to ignore this.
     if ($this->config->getValue('environment') !== 'development') {
         $cachePath = $this->config->getValue('cache/dir') . DIRECTORY_SEPARATOR . str_replace('\\', '_', $className) . '.php';
         if (is_readable($cachePath)) {
             $res = fopen($cachePath, 'r');
             $str = fread($res, 384);
             $success = preg_match('/' . Dictionaries\Placeholders::ORIGINAL_PATH_HINT . '(.+)' . Dictionaries\Placeholders::ORIGINAL_PATH_HINT . '/', $str, $tmp);
             if ($success > 0) {
                 $tmp = explode('#', $tmp[1]);
                 $path = $tmp[0];
                 $mTime = $tmp[1];
                 if (filemtime($path) == $mTime) {
                     // the cached file is recent, load it
                     require $cachePath;
                     return true;
                 }
             }
         }
     }
     // If we are loading something that the autoloader needs to function, then we have to skip to composer
     if (strpos($className, 'AppserverIo\\Doppelgaenger') === 0 && strpos($className, 'AppserverIo\\Doppelgaenger\\Tests') === false || strpos($className, 'PHP') === 0 || strpos($className, 'AppserverIo\\Psr\\MetaobjectProtocol') === 0 || strpos($className, 'AppserverIo\\Lang\\') === 0) {
         return false;
     }
     // If the structure map did not get filled by now we will do so here
     if ($this->structureMap->isEmpty()) {
         $this->structureMap->fill();
     }
     // Get the file from the map
     $file = $this->structureMap->getEntry($className);
     // Did we get something? If not return false.
     if ($file === false) {
         return false;
     }
     // We are still here, so we know the class and it is not omitted. Does it contain annotations then?
     if (!$file->hasAnnotations() || !$file->isEnforced()) {
         // on un-enforced classes we will require the original
         require $file->getPath();
         return true;
     }
     // So we have to create a new class definition for this original class.
     // Get a current cache instance if we do not have one already.
     if ($this->cache === null) {
         // We also require the classes of our maps as we do not have proper autoloading in place
         $this->cache = new CacheMap($this->getConfig()->getValue('cache/dir'), array(), $this->config);
     }
     $this->generator = new Generator($this->structureMap, $this->cache, $this->config, $this->aspectRegister);
     // Create the new class definition
     if ($this->generator->create($file, $this->config->getValue('enforcement/contract-inheritance')) === true) {
         // Require the new class, it should have been created now
         $file = $this->generator->getFileName($className);
         if ($file !== false && is_readable($file) === true) {
             require $file;
             return true;
         }
     } else {
         return false;
     }
     // Still here? That sounds like bad news!
     return false;
 }
 /**
  * Test the unsetValue() method
  *
  * @return void
  */
 public function testUnsetValue()
 {
     // Get our config
     $config = new Config();
     // Unset some values and test if they do not exist anymore
     $this->assertTrue($config->hasValue('environment'));
     $config->unsetValue('environment');
     $this->assertFalse($config->hasValue('environment'));
     // Do the same for a more "complex" index
     $this->assertTrue($config->hasValue('enforcement/enforce-default-type-safety'));
     $config->unsetValue('enforcement/enforce-default-type-safety');
     $this->assertFalse($config->hasValue('enforcement/enforce-default-type-safety'));
 }
 /**
  * Will append all needed filters based on the enforcement level stated in the configuration file.
  *
  * @param resource                                                           $res                 The resource we will append the filters to
  * @param \AppserverIo\Doppelgaenger\Interfaces\StructureDefinitionInterface $structureDefinition Structure definition providing needed information
  *
  * @return array
  */
 protected function appendDefaultFilters(&$res, StructureDefinitionInterface $structureDefinition)
 {
     // resulting array with resources of appended filters
     $filters = array();
     // Lets get the enforcement level
     $levelArray = array();
     if ($this->config->hasValue('enforcement/level')) {
         $levelArray = array_reverse(str_split(decbin($this->config->getValue('enforcement/level'))));
     }
     // Whatever the enforcement level is, we will always need the skeleton filter.
     $filters['SkeletonFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\SkeletonFilter', $structureDefinition);
     // Now lets register and append the filters if they are mapped to a 1
     // Lets have a look at the precondition filter first
     if (isset($levelArray[0]) && $levelArray[0] == 1) {
         // Do we even got any preconditions?
         $filterNeeded = false;
         $iterator = $structureDefinition->getFunctionDefinitions()->getIterator();
         foreach ($iterator as $functionDefinition) {
             if ($functionDefinition->getAllPreconditions()->count() !== 0) {
                 $filterNeeded = true;
                 break;
             }
         }
         if ($filterNeeded) {
             $filters['PreconditionFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\PreconditionFilter', $structureDefinition->getFunctionDefinitions());
         }
     }
     // What about the post-condition filter?
     if (isset($levelArray[1]) && $levelArray[1] == 1) {
         // Do we even got any post-conditions?
         $filterNeeded = false;
         $iterator = $structureDefinition->getFunctionDefinitions()->getIterator();
         foreach ($iterator as $functionDefinition) {
             if ($functionDefinition->getAllPostconditions()->count() !== 0) {
                 $filterNeeded = true;
                 break;
             }
         }
         if ($filterNeeded) {
             $filters['PostconditionFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\PostconditionFilter', $structureDefinition->getFunctionDefinitions());
         }
     }
     // What about the invariant filter?
     if (isset($levelArray[2]) && $levelArray[2] == 1) {
         // Do we even got any invariants?
         if ($structureDefinition->getInvariants()->count(true) !== 0) {
             $filters['InvariantFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\InvariantFilter', $structureDefinition);
         }
     }
     // introductions make only sense for classes
     if ($structureDefinition instanceof ClassDefinition) {
         // add the filter used for introductions
         $filters['IntroductionFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\IntroductionFilter', $structureDefinition->getIntroductions());
     }
     // add the filter we need for our AOP advices
     $filters['AdviceFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\AdviceFilter', array('functionDefinitions' => $structureDefinition->getFunctionDefinitions(), 'aspectRegister' => $this->aspectRegister));
     // add the filter used to proxy to the actual implementation
     $filters['ProcessingFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\ProcessingFilter', $structureDefinition->getFunctionDefinitions());
     // We ALWAYS need the enforcement filter. Everything else would not make any sense
     $filters['EnforcementFilter'] = $this->appendFilter($res, 'AppserverIo\\Doppelgaenger\\StreamFilters\\EnforcementFilter', array('structureDefinition' => $structureDefinition, 'config' => $this->config));
     // at last we want to make the output beatiful and detect sysntax errors
     // $filters['BeautifyFilter'] = $this->appendFilter($res, 'AppserverIo\Doppelgaenger\StreamFilters\BeautifyFilter', array());
     return $filters;
 }