/**
  * Gets the ResourceAssociationSet instance for the given source association end,
  * Note: Wrapper for IDataServiceMetadataProvider::getResourceAssociationSet 
  * method implementation
  * 
  * @param ResourceSetWrapper $resourceSetWrapper Resource set of the source 
  *                                               association end
  * @param ResourceType       $resourceType       Resource type of the source 
  *                                               association end
  * @param ResourceProperty   $resourceProperty   Resource property of the source 
  *                                               association end
  * 
  * @return ResourceAssociationSet/NULL Returns ResourceAssociationSet for the source
  *                                             association end, NULL if no such 
  *                                             association end or resource set in the
  *                                             other end of the association is invisible
  */
 public function getResourceAssociationSet(ResourceSetWrapper $resourceSetWrapper, ResourceType $resourceType, ResourceProperty $resourceProperty)
 {
     $resourceType = $this->_getResourceTypeWherePropertyIsDeclared($resourceType, $resourceProperty);
     $cacheKey = $resourceSetWrapper->getName() . '_' . $resourceType->getName() . '_' . $resourceProperty->getName();
     if (array_key_exists($cacheKey, $this->_resourceAssociationSetCache)) {
         return $this->_resourceAssociationSetCache[$cacheKey];
     }
     $associationSet = $this->_metadataProvider->getResourceAssociationSet($resourceSetWrapper->getResourceSet(), $resourceType, $resourceProperty);
     if (!is_null($associationSet)) {
         $thisAssociationSetEnd = $associationSet->getResourceAssociationSetEnd($resourceSetWrapper->getResourceSet(), $resourceType, $resourceProperty);
         $relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd($resourceSetWrapper->getResourceSet(), $resourceType, $resourceProperty);
         //If $thisAssociationSetEnd or $relatedAssociationSetEnd
         //is null means the associationset
         //we got from the IDSMP::getResourceAssociationSet is invalid.
         //AssociationSet::getResourceAssociationSetEnd
         //return null, if AssociationSet's End1 or End2's resourceset name
         //is not matching with the name of
         //resource set wrapper (param1) and resource type is not assignable
         //from given resource type (param2)
         if (is_null($thisAssociationSetEnd) || is_null($relatedAssociationSetEnd)) {
             throw new ODataException(Messages::metadataQueryProviderWrapperIDSMPGetResourceSetReturnsInvalidResourceSet($resourceSetWrapper->getName(), $resourceType->getFullName(), $resourceProperty->getName()), 500);
         }
         $relatedResourceSetWrapper = $this->_validateResourceSetAndGetWrapper($relatedAssociationSetEnd->getResourceSet());
         if ($relatedResourceSetWrapper === null) {
             $associationSet = null;
         } else {
             $this->_validateResourceType($thisAssociationSetEnd->getResourceType());
             $this->_validateResourceType($relatedAssociationSetEnd->getResourceType());
         }
     }
     $this->_resourceAssociationSetCache[$cacheKey] = $associationSet;
     return $associationSet;
 }
 /**
  * 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;
 }