Пример #1
0
 /**
  * Parse the given skiptoken, validate it using the given InternalOrderByInfo 
  * and generates instance of InternalSkipTokenInfo.
  * 
  * @param ResourceType        &$resourceType        The resource type of the
  *                                                  resource targeted by the
  *                                                  resource path.
  * @param InternalOrderByInfo &$internalOrderByInfo The $orderby details.
  * @param string              $skipToken            The $skiptoken value.
  * 
  * @return InternalSkipTokenInfo
  * 
  * @throws ODataException
  */
 public static function parseSkipTokenClause(ResourceType &$resourceType, InternalOrderByInfo &$internalOrderByInfo, $skipToken)
 {
     $tokenValueDescriptor = null;
     if (!KeyDescriptor::tryParseValuesFromSkipToken($skipToken, $tokenValueDescriptor)) {
         throw ODataException::createSyntaxError(Messages::skipTokenParserSyntaxError($skipToken));
     }
     $orderByPathSegments = null;
     //$positionalValues are of type array(int, array(string, IType))
     $positionalValues =& $tokenValueDescriptor->getPositionalValuesByRef();
     $count = count($positionalValues);
     $orderByPathSegments = $internalOrderByInfo->getOrderByPathSegments();
     $orderByPathCount = count($orderByPathSegments);
     if ($count != $orderByPathCount) {
         throw ODataException::createBadRequestError(Messages::skipTokenParserSkipTokenNotMatchingOrdering($count, $skipToken, $orderByPathCount));
     }
     $i = 0;
     foreach ($orderByPathSegments as $orderByPathSegment) {
         $typeProvidedInSkipToken = $positionalValues[$i][1];
         if (!$typeProvidedInSkipToken instanceof Null1) {
             $orderBySubPathSegments = $orderByPathSegment->getSubPathSegments();
             $j = count($orderBySubPathSegments) - 1;
             $expectedType = $orderBySubPathSegments[$j]->getInstanceType();
             if (!$expectedType->isCompatibleWith($typeProvidedInSkipToken)) {
                 throw ODataException::createSyntaxError(Messages::skipTokenParserInCompatibleTypeAtPosition($skipToken, $expectedType->getFullTypeName(), $i, $typeProvidedInSkipToken->getFullTypeName()));
             }
         }
         $i++;
     }
     return new InternalSkipTokenInfo($internalOrderByInfo, $positionalValues, $resourceType);
 }
Пример #2
0
 /**
  * Process the request Uri and creates an instance of
  * RequestDescription from the processed uri.
  * 
  * @param IService $service        Reference to the data service instance.
  *
  * @return RequestDescription
  * 
  * @throws ODataException If any exception occurs while processing the segments
  *                        or in case of any version incompatibility.
  */
 public static function process(IService $service)
 {
     $host = $service->getHost();
     $absoluteRequestUri = $host->getAbsoluteRequestUri();
     $absoluteServiceUri = $host->getAbsoluteServiceUri();
     $requestUriSegments = array_slice($absoluteRequestUri->getSegments(), $absoluteServiceUri->getSegmentCount());
     $segments = SegmentParser::parseRequestUriSegments($requestUriSegments, $service->getProvidersWrapper(), true);
     $request = new RequestDescription($segments, $absoluteRequestUri, $service->getConfiguration()->getMaxDataServiceVersion(), $host->getRequestVersion(), $host->getRequestMaxVersion());
     $kind = $request->getTargetKind();
     if ($kind == TargetKind::METADATA() || $kind == TargetKind::BATCH() || $kind == TargetKind::SERVICE_DIRECTORY()) {
         return $request;
     }
     if ($kind == TargetKind::PRIMITIVE_VALUE() || $kind == TargetKind::MEDIA_RESOURCE()) {
         // http://odata/NW.svc/Orders/$count
         // http://odata/NW.svc/Orders(123)/Customer/CustomerID/$value
         // http://odata/NW.svc/Employees(1)/$value
         // http://odata/NW.svc/Employees(1)/ThumbNail_48X48/$value
         $request->setContainerName($segments[count($segments) - 2]->getIdentifier());
     } else {
         $request->setContainerName($request->getIdentifier());
     }
     if ($request->getIdentifier() === ODataConstants::URI_COUNT_SEGMENT) {
         if (!$service->getConfiguration()->getAcceptCountRequests()) {
             throw ODataException::createBadRequestError(Messages::configurationCountNotAccepted());
         }
         $request->queryType = QueryType::COUNT();
         // use of $count requires request DataServiceVersion
         // and MaxDataServiceVersion greater than or equal to 2.0
         $request->raiseResponseVersion(2, 0);
         $request->raiseMinVersionRequirement(2, 0);
     } else {
         if ($request->isNamedStream()) {
             $request->raiseMinVersionRequirement(3, 0);
         } else {
             if ($request->getTargetKind() == TargetKind::RESOURCE()) {
                 if (!$request->isLinkUri()) {
                     $resourceSetWrapper = $request->getTargetResourceSetWrapper();
                     //assert($resourceSetWrapper != null)
                     $hasNamedStream = $resourceSetWrapper->hasNamedStreams($service->getProvidersWrapper());
                     $hasBagProperty = $resourceSetWrapper->hasBagProperty($service->getProvidersWrapper());
                     if ($hasNamedStream || $hasBagProperty) {
                         $request->raiseResponseVersion(3, 0);
                     }
                 }
             } else {
                 if ($request->getTargetKind() == TargetKind::BAG()) {
                     $request->raiseResponseVersion(3, 0);
                 }
             }
         }
     }
     return $request;
 }
Пример #3
0
 /**
  * For the given entry object compare it's eTag (if it has eTag properties)
  * with current eTag request headers (if it present).
  * 
  * @param mixed        &$entryObject             entity resource for which etag 
  *                                               needs to be checked.
  * @param ResourceType &$resourceType            Resource type of the entry 
  *                                               object.
  * @param boolean      &$needToSerializeResponse On return, this will contain 
  *                                               True if response needs to be
  *                                               serialized, False otherwise.
  *                                              
  * @return string|null The ETag for the entry object if it has eTag properties 
  *                     NULL otherwise.
  */
 protected function compareETag(&$entryObject, ResourceType &$resourceType, &$needToSerializeResponse)
 {
     $needToSerializeResponse = true;
     $eTag = null;
     $ifMatch = $this->_serviceHost->getRequestIfMatch();
     $ifNoneMatch = $this->_serviceHost->getRequestIfNoneMatch();
     if (is_null($entryObject)) {
         if (!is_null($ifMatch)) {
             throw ODataException::createPreConditionFailedError(Messages::eTagNotAllowedForNonExistingResource());
         }
         return null;
     }
     if ($this->config->getValidateETagHeader() && !$resourceType->hasETagProperties()) {
         if (!is_null($ifMatch) || !is_null($ifNoneMatch)) {
             // No eTag properties but request has eTag headers, bad request
             throw ODataException::createBadRequestError(Messages::noETagPropertiesForType());
         }
         // We need write the response but no eTag header
         return null;
     }
     if (!$this->config->getValidateETagHeader()) {
         // Configuration says do not validate ETag so we will not write ETag header in the
         // response even though the requested resource support it
         return null;
     }
     if (is_null($ifMatch) && is_null($ifNoneMatch)) {
         // No request eTag header, we need to write the response
         // and eTag header
     } else {
         if (strcmp($ifMatch, '*') == 0) {
             // If-Match:* => we need to write the response and eTag header
         } else {
             if (strcmp($ifNoneMatch, '*') == 0) {
                 // if-None-Match:* => Do not write the response (304 not modified),
                 // but write eTag header
                 $needToSerializeResponse = false;
             } else {
                 $eTag = $this->getETagForEntry($entryObject, $resourceType);
                 // Note: The following code for attaching the prefix W\"
                 // and the suffix " can be done in getETagForEntry function
                 // but that is causing an issue in Linux env where the
                 // firefix browser is unable to parse the ETag in this case.
                 // Need to follow up PHP core devs for this.
                 $eTag = ODataConstants::HTTP_WEAK_ETAG_PREFIX . $eTag . '"';
                 if (!is_null($ifMatch)) {
                     if (strcmp($eTag, $ifMatch) != 0) {
                         // Requested If-Match value does not match with current
                         // eTag Value then pre-condition error
                         // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
                         throw ODataException::createPreConditionFailedError(Messages::eTagValueDoesNotMatch());
                     }
                 } else {
                     if (strcmp($eTag, $ifNoneMatch) == 0) {
                         //304 not modified, but in write eTag header
                         $needToSerializeResponse = false;
                     }
                 }
             }
         }
     }
     if (is_null($eTag)) {
         $eTag = $this->getETagForEntry($entryObject, $resourceType);
         // Note: The following code for attaching the prefix W\"
         // and the suffix " can be done in getETagForEntry function
         // but that is causing an issue in Linux env where the
         // firefix browser is unable to parse the ETag in this case.
         // Need to follow up PHP core devs for this.
         $eTag = ODataConstants::HTTP_WEAK_ETAG_PREFIX . $eTag . '"';
     }
     return $eTag;
 }
Пример #4
0
 /**
  * Validates the given version in string format and returns the version as instance of Version
  * 
  * @param string $versionHeader The DataServiceVersion or MaxDataServiceVersion header value
  * @param string $headerName    The name of the header
  * 
  * @return Version
  * 
  * @throws ODataException If the version is malformed or not supported
  */
 private static function parseVersionHeader($versionHeader, $headerName)
 {
     $libName = null;
     $versionHeader = trim($versionHeader);
     $libNameIndex = strpos($versionHeader, ';');
     if ($libNameIndex !== false) {
         $libName = substr($versionHeader, $libNameIndex);
     } else {
         $libNameIndex = strlen($versionHeader);
     }
     $dotIndex = -1;
     for ($i = 0; $i < $libNameIndex; $i++) {
         if ($versionHeader[$i] == '.') {
             //Throw an exception if we find more than 1 dot
             if ($dotIndex != -1) {
                 throw ODataException::createBadRequestError(Messages::requestDescriptionInvalidVersionHeader($versionHeader, $headerName));
             }
             $dotIndex = $i;
         } else {
             if ($versionHeader[$i] < '0' || $versionHeader[$i] > '9') {
                 throw ODataException::createBadRequestError(Messages::requestDescriptionInvalidVersionHeader($versionHeader, $headerName));
             }
         }
     }
     $major = intval(substr($versionHeader, 0, $dotIndex));
     $minor = 0;
     //Apparently the . is optional
     if ($dotIndex != -1) {
         if ($dotIndex == 0) {
             //If it starts with a ., throw an exception
             throw ODataException::createBadRequestError(Messages::requestDescriptionInvalidVersionHeader($versionHeader, $headerName));
         }
         $minor = intval(substr($versionHeader, $dotIndex + 1, $libNameIndex));
     }
     $version = new Version($major, $minor);
     //TODO: move this somewhere...
     /*
             $isSupportedVersion = false;
             foreach (self::getKnownDataServiceVersions() as $version1) {
                 if ($version->compare($version1) == 0) {
                     $isSupportedVersion = true;
                     break;
                 }
             }
     
             if (!$isSupportedVersion) {
                 $availableVersions = null;
                 foreach (self::getKnownDataServiceVersions() as $version1) {
                     $availableVersions .= $version1->toString() . ', ';
                 }
     
                 $availableVersions = rtrim($availableVersions, ', ');
                 throw ODataException::createBadRequestError(
                     Messages::requestDescriptionUnSupportedVersion(
                         $headerName,
                         $versionHeader,
                 $availableVersions
                     )
                 );
             }
     */
     return $version;
 }
Пример #5
0
 /**
  * This method verfies the client provided url query parameters and check whether
  * any of the odata query option specified more than once or check any of the 
  * non-odata query parameter start will $ symbol or check any of the odata query 
  * option specified with out value. If any of the above check fails throws 
  * ODataException, else set _queryOptions member variable
  * 
  * @return void
  * 
  * @throws ODataException
  */
 public function validateQueryParameters()
 {
     $queryOptions = $this->_operationContext->incomingRequest()->getQueryParameters();
     reset($queryOptions);
     $namesFound = array();
     while ($queryOption = current($queryOptions)) {
         $optionName = key($queryOption);
         $optionValue = current($queryOption);
         if (empty($optionName)) {
             if (!empty($optionValue)) {
                 if ($optionValue[0] == '$') {
                     if ($this->_isODataQueryOption($optionValue)) {
                         throw ODataException::createBadRequestError(Messages::hostODataQueryOptionFoundWithoutValue($optionValue));
                     } else {
                         throw ODataException::createBadRequestError(Messages::hostNonODataOptionBeginsWithSystemCharacter($optionValue));
                     }
                 }
             }
         } else {
             if ($optionName[0] == '$') {
                 if (!$this->_isODataQueryOption($optionName)) {
                     throw ODataException::createBadRequestError(Messages::hostNonODataOptionBeginsWithSystemCharacter($optionName));
                 }
                 if (array_search($optionName, $namesFound) !== false) {
                     throw ODataException::createBadRequestError(Messages::hostODataQueryOptionCannotBeSpecifiedMoreThanOnce($optionName));
                 }
                 if (empty($optionValue) && $optionValue !== '0') {
                     throw ODataException::createBadRequestError(Messages::hostODataQueryOptionFoundWithoutValue($optionName));
                 }
                 $namesFound[] = $optionName;
             }
         }
         next($queryOptions);
     }
     $this->_queryOptions = $queryOptions;
 }
Пример #6
0
 /**
  * Modify the 'Projection Tree' to include selection details
  * 
  * @param array(array(string)) $selectPathSegments Collection of select 
  *                                                 paths.
  * 
  * @return void
  * 
  * @throws ODataException If any error occurs while processing select
  *                        path segments
  */
 private function _applySelectionToProjectionTree($selectPathSegments)
 {
     foreach ($selectPathSegments as $selectSubPathSegments) {
         $currentNode = $this->_rootProjectionNode;
         $subPathCount = count($selectSubPathSegments);
         foreach ($selectSubPathSegments as $index => $selectSubPathSegment) {
             if (!$currentNode instanceof RootProjectionNode && !$currentNode instanceof ExpandedProjectionNode) {
                 throw ODataException::createBadRequestError(Messages::expandProjectionParserPropertyWithoutMatchingExpand($currentNode->getPropertyName()));
             }
             $currentNode->setSelectionFound();
             $isLastSegment = $index == $subPathCount - 1;
             if ($selectSubPathSegment === '*') {
                 $currentNode->setSelectAllImmediateProperties();
                 break;
             }
             $currentResourceType = $currentNode->getResourceType();
             $resourceProperty = $currentResourceType->resolveProperty($selectSubPathSegment);
             if (is_null($resourceProperty)) {
                 throw ODataException::createSyntaxError(Messages::expandProjectionParserPropertyNotFound($currentResourceType->getFullName(), $selectSubPathSegment, true));
             }
             if (!$isLastSegment) {
                 if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) {
                     throw ODataException::createBadRequestError(Messages::expandProjectionParserBagPropertyAsInnerSelectSegment($currentResourceType->getFullName(), $selectSubPathSegment));
                 } else {
                     if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) {
                         throw ODataException::createBadRequestError(Messages::expandProjectionParserPrimitivePropertyUsedAsNavigationProperty($currentResourceType->getFullName(), $selectSubPathSegment));
                     } else {
                         if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) {
                             throw ODataException::createBadRequestError(Messages::expandProjectionParserComplexPropertyAsInnerSelectSegment($currentResourceType->getFullName(), $selectSubPathSegment));
                         } else {
                             if ($resourceProperty->getKind() != ResourcePropertyKind::RESOURCE_REFERENCE && $resourceProperty->getKind() != ResourcePropertyKind::RESOURCESET_REFERENCE) {
                                 throw ODataException::createInternalServerError(Messages::expandProjectionParserUnexpectedPropertyType());
                             }
                         }
                     }
                 }
             }
             $node = $currentNode->findNode($selectSubPathSegment);
             if (is_null($node)) {
                 if (!$isLastSegment) {
                     throw ODataException::createBadRequestError(Messages::expandProjectionParserPropertyWithoutMatchingExpand($selectSubPathSegment));
                 }
                 $node = new ProjectionNode($selectSubPathSegment, $resourceProperty);
                 $currentNode->addNode($node);
             }
             $currentNode = $node;
             if ($currentNode instanceof ExpandedProjectionNode && $isLastSegment) {
                 $currentNode->setSelectionFound();
                 $currentNode->markSubtreeAsSelected();
             }
         }
     }
 }
Пример #7
0
 /**
  * Create SegmentDescriptor for the first segment
  * 
  * @param string $segmentIdentifier The identifier part of the first segment
  * @param string $keyPredicate The predicate part of the first segment if any else NULL
  * @param boolean $checkRights Whether to check the rights on this segment
  *
  * @return SegmentDescriptor Descriptor for the first segment
  * 
  * @throws ODataException Exception if any validation fails
  */
 private function _createFirstSegmentDescriptor($segmentIdentifier, $keyPredicate, $checkRights)
 {
     $descriptor = new SegmentDescriptor();
     $descriptor->setIdentifier($segmentIdentifier);
     if ($segmentIdentifier === ODataConstants::URI_METADATA_SEGMENT) {
         $this->_assertion(is_null($keyPredicate));
         $descriptor->setTargetKind(TargetKind::METADATA());
         return $descriptor;
     }
     if ($segmentIdentifier === ODataConstants::URI_BATCH_SEGMENT) {
         $this->_assertion(is_null($keyPredicate));
         $descriptor->setTargetKind(TargetKind::BATCH());
         return $descriptor;
     }
     if ($segmentIdentifier === ODataConstants::URI_COUNT_SEGMENT) {
         throw ODataException::createBadRequestError(Messages::segmentParserSegmentNotAllowedOnRoot(ODataConstants::URI_COUNT_SEGMENT));
     }
     if ($segmentIdentifier === ODataConstants::URI_LINK_SEGMENT) {
         throw ODataException::createBadRequestError(Messages::segmentParserSegmentNotAllowedOnRoot(ODataConstants::URI_LINK_SEGMENT));
     }
     $resourceSetWrapper = $this->providerWrapper->resolveResourceSet($segmentIdentifier);
     if ($resourceSetWrapper === null) {
         throw ODataException::createResourceNotFoundError($segmentIdentifier);
     }
     $descriptor->setTargetResourceSetWrapper($resourceSetWrapper);
     $descriptor->setTargetResourceType($resourceSetWrapper->getResourceType());
     $descriptor->setTargetSource(TargetSource::ENTITY_SET);
     $descriptor->setTargetKind(TargetKind::RESOURCE());
     if ($keyPredicate !== null) {
         $keyDescriptor = $this->_createKeyDescriptor($segmentIdentifier . '(' . $keyPredicate . ')', $resourceSetWrapper->getResourceType(), $keyPredicate);
         $descriptor->setKeyDescriptor($keyDescriptor);
         if (!$keyDescriptor->isEmpty()) {
             $descriptor->setSingleResult(true);
         }
     }
     if ($checkRights) {
         $resourceSetWrapper->checkResourceSetRightsForRead($descriptor->isSingleResult());
     }
     return $descriptor;
 }
Пример #8
0
 /**
  * To check whether the the query options $select, $expand
  * is applicable for the current requested resource.
  * 
  * @param string $queryItem The query option to check.
  * 
  * @return void
  * 
  * @throws ODataException Throws bad request error if the query 
  *                        options $select, $expand cannot be 
  *                        applied to the requested resource. 
  */
 private function _checkExpandOrSelectApplicable($queryItem)
 {
     if (!$this->_expandSelectApplicable) {
         throw ODataException::createBadRequestError(Messages::queryProcessorSelectOrExpandOptionNotApplicable($queryItem));
     }
 }
Пример #9
0
 /**
  * Build 'OrderBy Tree' from the given orderby path segments, also build 
  * comparsion function for each path segment.
  * 
  * @param array(array) &$orderByPathSegments Collection of orderby path segments,
  *                                           this is passed by reference
  *                                           since we need this function to 
  *                                           modify this array in two cases:
  *                                           1. if asc or desc present, then the 
  *                                              corresponding sub path segment 
  *                                              should be removed
  *                                           2. remove duplicate orderby path 
  *                                              segment
  * 
  * @return void
  * 
  * @throws ODataException If any error occurs while processing the orderby path 
  *                        segments
  */
 private function _buildOrderByTree(&$orderByPathSegments)
 {
     foreach ($orderByPathSegments as $index1 => &$orderBySubPathSegments) {
         $currentNode = $this->_rootOrderByNode;
         $currentObject = $this->_dummyObject;
         $ascending = true;
         $subPathCount = count($orderBySubPathSegments);
         // Check sort order is specified in the path, if so set a
         // flag and remove that segment
         if ($subPathCount > 1) {
             if ($orderBySubPathSegments[$subPathCount - 1] === '*desc') {
                 $ascending = false;
                 unset($orderBySubPathSegments[$subPathCount - 1]);
                 $subPathCount--;
             } else {
                 if ($orderBySubPathSegments[$subPathCount - 1] === '*asc') {
                     unset($orderBySubPathSegments[$subPathCount - 1]);
                     $subPathCount--;
                 }
             }
         }
         $ancestors = array($this->_rootOrderByNode->getResourceSetWrapper()->getName());
         foreach ($orderBySubPathSegments as $index2 => $orderBySubPathSegment) {
             $isLastSegment = $index2 == $subPathCount - 1;
             $resourceSetWrapper = null;
             $resourceType = $currentNode->getResourceType();
             $resourceProperty = $resourceType->resolveProperty($orderBySubPathSegment);
             if (is_null($resourceProperty)) {
                 throw ODataException::createSyntaxError(Messages::orderByParserPropertyNotFound($resourceType->getFullName(), $orderBySubPathSegment));
             }
             if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) {
                 throw ODataException::createBadRequestError(Messages::orderByParserBagPropertyNotAllowed($resourceProperty->getName()));
             } else {
                 if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) {
                     if (!$isLastSegment) {
                         throw ODataException::createBadRequestError(Messages::orderByParserPrimitiveAsIntermediateSegment($resourceProperty->getName()));
                     }
                     $type = $resourceProperty->getInstanceType();
                     if ($type instanceof Binary) {
                         throw ODataException::createBadRequestError(Messages::orderByParserSortByBinaryPropertyNotAllowed($resourceProperty->getName()));
                     }
                 } else {
                     if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE || $resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE) {
                         $this->_assertion($currentNode instanceof OrderByRootNode || $currentNode instanceof OrderByNode);
                         $resourceSetWrapper = $currentNode->getResourceSetWrapper();
                         $this->_assertion(!is_null($resourceSetWrapper));
                         $resourceSetWrapper = $this->_providerWrapper->getResourceSetWrapperForNavigationProperty($resourceSetWrapper, $resourceType, $resourceProperty);
                         if (is_null($resourceSetWrapper)) {
                             throw ODataException::createBadRequestError(Messages::badRequestInvalidPropertyNameSpecified($resourceType->getFullName(), $orderBySubPathSegment));
                         }
                         if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE) {
                             throw ODataException::createBadRequestError(Messages::orderByParserResourceSetReferenceNotAllowed($resourceProperty->getName(), $resourceType->getFullName()));
                         }
                         $resourceSetWrapper->checkResourceSetRightsForRead(true);
                         if ($isLastSegment) {
                             throw ODataException::createBadRequestError(Messages::orderByParserSortByNavigationPropertyIsNotAllowed($resourceProperty->getName()));
                         }
                         $ancestors[] = $orderBySubPathSegment;
                     } else {
                         if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) {
                             if ($isLastSegment) {
                                 throw ODataException::createBadRequestError(Messages::orderByParserSortByComplexPropertyIsNotAllowed($resourceProperty->getName()));
                             }
                             $ancestors[] = $orderBySubPathSegment;
                         } else {
                             throw ODataException::createInternalServerError(Messages::orderByParserUnexpectedPropertyType());
                         }
                     }
                 }
             }
             $node = $currentNode->findNode($orderBySubPathSegment);
             if (is_null($node)) {
                 if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) {
                     $node = new OrderByLeafNode($orderBySubPathSegment, $resourceProperty, $ascending);
                     $this->_comparisonFunctions[] = $node->buildComparisonFunction($ancestors);
                 } else {
                     if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE) {
                         $node = new OrderByNode($orderBySubPathSegment, $resourceProperty, $resourceSetWrapper);
                         // Initialize this member variable (identified by
                         // $resourceProperty) of parent object.
                         try {
                             $dummyProperty = new \ReflectionProperty($currentObject, $resourceProperty->getName());
                             $object = $resourceProperty->getInstanceType()->newInstance();
                             $dummyProperty->setValue($currentObject, $object);
                             $currentObject = $object;
                         } catch (\ReflectionException $reflectionException) {
                             throw ODataException::createInternalServerError(Messages::orderByParserFailedToAccessOrInitializeProperty($resourceProperty->getName(), $resourceType->getName()));
                         }
                     } else {
                         if ($resourceProperty->getKind() == ResourcePropertyKind::COMPLEX_TYPE) {
                             $node = new OrderByNode($orderBySubPathSegment, $resourceProperty, null);
                             // Initialize this member variable
                             // (identified by $resourceProperty)of parent object.
                             try {
                                 $dummyProperty = new \ReflectionProperty($currentObject, $resourceProperty->getName());
                                 $object = $resourceProperty->getInstanceType()->newInstance();
                                 $dummyProperty->setValue($currentObject, $object);
                                 $currentObject = $object;
                             } catch (\ReflectionException $reflectionException) {
                                 throw ODataException::createInternalServerError(Messages::orderByParserFailedToAccessOrInitializeProperty($resourceProperty->getName(), $resourceType->getName()));
                             }
                         }
                     }
                 }
                 $currentNode->addNode($node);
             } else {
                 try {
                     $reflectionClass = new \ReflectionClass(get_class($currentObject));
                     $reflectionProperty = $reflectionClass->getProperty($resourceProperty->getName());
                     $reflectionProperty->setAccessible(true);
                     $currentObject = $reflectionProperty->getValue($currentObject);
                     //$dummyProperty = new \ReflectionProperty(
                     //    $currentObject, $resourceProperty->getName()
                     //);
                     //$currentObject = $dummyProperty->getValue($currentObject);
                 } catch (\ReflectionException $reflectionException) {
                     throw ODataException::createInternalServerError(Messages::orderByParserFailedToAccessOrInitializeProperty($resourceProperty->getName(), $resourceType->getName()));
                 }
                 if ($node instanceof OrderByLeafNode) {
                     //remove duplicate orderby path
                     unset($orderByPathSegments[$index1]);
                 }
             }
             $currentNode = $node;
         }
     }
 }