/**
  * Iterate over the resource type of the given resource set, 
  * derived resource types base resource types and complex types 
  * used in these resource types and cache them.
  * 
  * @param ResourceSetWrapper $resourceSetWrapper The resource set to inspect
  * 
  * @return void
  * 
  * @throws InvalidOperationException Throws exception in floowing cases:
  * (1) If IDSMP::getDerivedTypes returns any type other than null or array
  * (2) If Named streams are found on derived types
  */
 private function _populateResourceTypeForSet(ResourceSetWrapper $resourceSetWrapper)
 {
     $derivedTypes = $this->metadataQueryproviderWrapper->getDerivedTypes($resourceSetWrapper->getResourceType());
     if (!is_null($derivedTypes)) {
         if (!is_array($derivedTypes)) {
             throw new InvalidOperationException(Messages::metadataAssociationTypeSetInvalidGetDerivedTypesReturnType($resourceSetWrapper->getName()));
         }
         //Populate Resource type for derived types and
         //complex types in derived types
         foreach ($derivedTypes as $derivedType) {
             if ($derivedType->hasNamedStream()) {
                 throw new InvalidOperationException(Messages::metadataResourceTypeSetNamedStreamsOnDerivedEntityTypesNotSupported($resourceSetWrapper->getName(), $derivedType->getFullName()));
             }
             $this->_populateResourceTypes($derivedType);
             $this->_populateComplexTypes($derivedType);
         }
     }
     //Populate Resource type for for this type and
     //base types and complex types in this type and base types
     $resourceType = $resourceSetWrapper->getResourceType();
     while ($resourceType != null) {
         $this->_populateResourceTypes($resourceType);
         $this->_populateComplexTypes($resourceType);
         $resourceType = $resourceType->getBaseType();
     }
 }
 /**
  * This function perfrom the following operations
  *  (1) If the cache contain an entry [key, value] for the resourceset then 
  *      return the entry-value
  *  (2) If the cache not contain an entry for the resourceset then validate 
  *      the resourceset
  *            (a) If valid add entry as [resouceset_name, resourceSetWrapper]
  *            (b) if not valid add entry as [resouceset_name, null]
  *  Note: validating a resourceset means checking the resourceset is visible 
  *  or not using configuration
  *  
  * @param ResourceSet $resourceSet The resourceset to validate and get the 
  *                                 wrapper for
  * 
  * @return ResourceSetWrapper/NULL Returns an instance if ResourceSetWrapper 
  *     if resourceset is visible else NULL
  */
 private function _validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
 {
     $cacheKey = $resourceSet->getName();
     if (array_key_exists($cacheKey, $this->_resourceSetWrapperCache)) {
         return $this->_resourceSetWrapperCache[$cacheKey];
     }
     $this->_validateResourceType($resourceSet->getResourceType());
     $resourceSetWrapper = new ResourceSetWrapper($resourceSet, $this->_configuration);
     if ($resourceSetWrapper->isVisible()) {
         $this->_resourceSetWrapperCache[$cacheKey] = $resourceSetWrapper;
     } else {
         $this->_resourceSetWrapperCache[$cacheKey] = null;
     }
     return $this->_resourceSetWrapperCache[$cacheKey];
 }
 /**
  * Gets the ResourceAssociationType instance for the given 
  * ResourceAssociationSet and one of it's end.
  *       
  * This function first searches the ResourceAssociationType cache, 
  * if found return it otherwise create the Association type for the given 
  * association set, cache and return it.
  * 
  * Creation of ResourceAssociationType includes two sub-tasks:
  *  1. Deciding name of 'ResourceAssociationType' 
  *  (see the function _getAssociationTypeName)
  *  2. Deciding names for two 'ResourceAssociationTypeEnd' of the 
  *  'ResourceAssociationType'
  *  Refer ./AssociationSetAndTypeNamingRules.txt for naming rules.
  *   
  * @param ResourceAssociationSet $resourceAssociationSet Association set to
  *                                                       get the 
  *                                                       association type
  * @param ResourceSetWrapper     $resourceSet            Resource set for
  *                                                       one of the ends of 
  *                                                       given association set
  * @param ResourceType           $resourceType           Resource type for 
  *                                                       one of the ends of 
  *                                                       given association set
  * @param ResourceProperty       $navigationProperty     Resource property for 
  *                                                       one of the ends of 
  *                                                       given association set
  * 
  * @return ResourceAssociationType The association type 
  * for the given association set
  */
 private function _getResourceAssociationType(ResourceAssociationSet $resourceAssociationSet, ResourceSetWrapper $resourceSet, ResourceType $resourceType, ResourceProperty $navigationProperty)
 {
     $resourceTypeNamespace = $this->getResourceTypeNamespace($resourceType);
     $resourceAssociationTypesInNamespace =& $this->getResourceAssociationTypesForNamespace($resourceTypeNamespace);
     $associationTypeLookupKey = $resourceType->getName() . '_' . $navigationProperty->getName();
     if (array_key_exists($associationTypeLookupKey, $resourceAssociationTypesInNamespace)) {
         return $resourceAssociationTypesInNamespace[$associationTypeLookupKey];
     }
     //Generate resource association type end names
     //Refer ./AssociationSetAndTypeNamingRules.txt
     $associationTypeEnd1Name = $associationTypeEnd2Name = null;
     $isBiDirectional = $resourceAssociationSet->isBidirectional();
     if ($isBiDirectional) {
         $associationTypeEnd1Name = $resourceAssociationSet->getEnd1()->getResourceType()->getName() . '_' . $resourceAssociationSet->getEnd1()->getResourceProperty()->getName();
         $associationTypeEnd2Name = $resourceAssociationSet->getEnd2()->getResourceType()->getName() . '_' . $resourceAssociationSet->getEnd2()->getResourceProperty()->getName();
     } else {
         if (!is_null($resourceAssociationSet->getEnd1()->getResourceProperty())) {
             $associationTypeEnd1Name = $resourceAssociationSet->getEnd1()->getResourceType()->getName();
             $associationTypeEnd2Name = $resourceAssociationSet->getEnd1()->getResourceProperty()->getName();
         } else {
             $associationTypeEnd1Name = $resourceAssociationSet->getEnd2()->getResourceProperty()->getName();
             $associationTypeEnd2Name = $resourceAssociationSet->getEnd2()->getResourceType()->getName();
         }
     }
     //Generate resource assoication type name
     //Refer ./AssociationSetAndTypeNamingRules.txt
     $resourceAssociationTypeName = $this->_getAssociationTypeName($resourceAssociationSet);
     //Create and cache the association type
     $resourceAssociationType = new ResourceAssociationType($resourceAssociationTypeName, $resourceTypeNamespace, new ResourceAssociationTypeEnd($associationTypeEnd1Name, $resourceAssociationSet->getEnd1()->getResourceType(), $resourceAssociationSet->getEnd1()->getResourceProperty(), $resourceAssociationSet->getEnd2()->getResourceProperty()), new ResourceAssociationTypeEnd($associationTypeEnd2Name, $resourceAssociationSet->getEnd2()->getResourceType(), $resourceAssociationSet->getEnd2()->getResourceProperty(), $resourceAssociationSet->getEnd1()->getResourceProperty()));
     $resourceAssociationTypesInNamespace[$associationTypeLookupKey] = $resourceAssociationType;
     if ($isBiDirectional) {
         $relatedAssociationSetEnd = $resourceAssociationSet->getRelatedResourceAssociationSetEnd($resourceSet->getResourceSet(), $resourceType, $navigationProperty);
         $relatedEndLookupKey = $relatedAssociationSetEnd->getResourceType()->getName() . '_' . $relatedAssociationSetEnd->getResourceProperty()->getName();
         $resourceAssociationTypesInNamespace[$relatedEndLookupKey] = $resourceAssociationType;
     }
     return $resourceAssociationType;
 }