public void AddOneToManyReachabilityAssociations(JObject data, IList <KeyValuePair <PathSegment, string> > pathSegmentsRepresentingStableUriPath, int statusCode, SKotstein.Net.Http.Context.HttpMethod method, string xPathPrefix) { //extract path segment representing the queried or manipulated resource (a check whether it exists has been already done before) PathSegment pathSegmentRepresentingQueriedOrManipulatedResource = pathSegmentsRepresentingStableUriPath[pathSegmentsRepresentingStableUriPath.Count - 1].Key; foreach (ReachabilityPath reachabilityAssociation in ((CustomizedPathSegment)pathSegmentRepresentingQueriedOrManipulatedResource).ReachabilityPaths) { //filter for one-to-one reachability associations if (reachabilityAssociation.Type == ReachabilityPathType.oneToMany) { foreach (Link link in reachabilityAssociation.Links) { //check whether status code matches documented status code in link if (link.StatusCode.CompareTo(statusCode + "") == 0) { //check whether method matches documented method in link switch (method) { case SKotstein.Net.Http.Context.HttpMethod.GET: if (link.Operation.Method != urimodel.HttpMethod.GET) { continue; } break; case SKotstein.Net.Http.Context.HttpMethod.PATCH: if (link.Operation.Method != urimodel.HttpMethod.PATCH) { continue; } break; case SKotstein.Net.Http.Context.HttpMethod.POST: if (link.Operation.Method != urimodel.HttpMethod.POST) { continue; } break; case SKotstein.Net.Http.Context.HttpMethod.PUT: if (link.Operation.Method != urimodel.HttpMethod.PUT) { continue; } break; case SKotstein.Net.Http.Context.HttpMethod.DELETE: if (link.Operation.Method != urimodel.HttpMethod.DELETE) { continue; } break; } } else { continue; } //load values string xPath = link.XPath.Replace("$", xPathPrefix); IEnumerable <JToken> values = data.SelectTokens(xPath); //iterate over values foreach (JToken value in values) { IDictionary <PathSegment, string> pathSegmentValues = ConvertListToDictionary(pathSegmentsRepresentingStableUriPath); //subsitutute path parameter IDictionary <PathParameter, string> pathParameterMapping = new Dictionary <PathParameter, string>(); pathParameterMapping.Add(link.PathParameter, (string)value); string substitutedVariablePathSegment = link.PathParameter.PathSegment.BuildStablePathSegment(pathParameterMapping); //add subsituted variable path segment pathSegmentValues.Add(link.PathParameter.PathSegment, substitutedVariablePathSegment); //create stable URI path pointing on target IList <KeyValuePair <PathSegment, string> > pathSegmentsToTarget = _uriModel.GetPathSegmentsByStablePathSegments(reachabilityAssociation.Target, pathSegmentValues); string pathToTarget = UriModel.BuildFullPath(pathSegmentsToTarget); //send pre-flight request: PreflightResult preflightResult = SendPreflight(pathToTarget); if (preflightResult.StatusCode < 200 || preflightResult.StatusCode >= 300) { if (_hyperlinkWithDebugInformation) { Hyperlink hyperlink = new Hyperlink() { Href = pathToTarget, Rel = ITEM_REL, Debug_statusCode = preflightResult.StatusCode, Debug_msg = preflightResult.Message }; this.AddObjectToLinksArray(value.Parent.Parent, hyperlink); } } else { Hyperlink hyperlink = new Hyperlink() { Href = pathToTarget, Rel = ITEM_REL }; this.AddObjectToLinksArray(value.Parent.Parent, hyperlink); } } } } } }
private string InjectHyperlinks(string content, string path, SKotstein.Net.Http.Context.HttpMethod method, int statusCode) { //step 1: determine the path segments that represents the queried/manipulated resource IList <KeyValuePair <PathSegment, string> > pathSegmentsRepresentingStableUriPath = _uriModel.GetPathSegmentsByStableUriPath(path); //check whether stable URI path could be mapped if (pathSegmentsRepresentingStableUriPath.Count == 0) { Log.Warning(TAG, "The stable URI path '" + path + "' cannot be mapped to path segments in the URI Model."); return(content); } //extract last path segment that represents the queried or manipulated resource PathSegment pathSegmentRepresentingQueriedOrManipulatedResource = pathSegmentsRepresentingStableUriPath[pathSegmentsRepresentingStableUriPath.Count - 1].Key; //check whether the mapped last path segment represents a resource endpoint if (!pathSegmentRepresentingQueriedOrManipulatedResource.HasOperations) { Log.Warning(TAG, "The stable URI path '" + path + "' is mapped to the path segment with the full URI path '" + pathSegmentRepresentingQueriedOrManipulatedResource.UriPath + "'. However, according to the URI Model, this path segment does not support any operation (i.e. does not represent a resource endpoint)."); return(content); } //print mapping (debug only) foreach (KeyValuePair <PathSegment, string> pathSegment in pathSegmentsRepresentingStableUriPath) { Log.Debug(TAG, "'" + pathSegment.Value + "' is mapped to '" + pathSegment.Key.Value + "'"); } //step 2: check whether content is empty if (String.IsNullOrWhiteSpace(content)) { Log.Warning(TAG, "The response payload is empty"); return(content); } //step 3: parse JSON JToken rawData = JToken.Parse(content); JObject data = null; string xPathPrefix = "$"; if (rawData is JObject) { data = (JObject)rawData; } else if (rawData is JArray) { data = new JObject(); data.Add("data", rawData); xPathPrefix = "$.data[*]"; } //JObject data = JObject.Parse(content); //step 4: add hyperlink to self AddHyperlinkToSelf(data, path); //step 5: add one-to-one reachability associations AddOneToOneReachabilityAssociations(data, pathSegmentsRepresentingStableUriPath); //step 6: add one-to-many reachability associations AddOneToManyReachabilityAssociations(data, pathSegmentsRepresentingStableUriPath, statusCode, method, xPathPrefix); //step 7: return modified value back return(JsonSerializer.SerializeJson(data)); }