public void IdentifyReachabilityPaths(ILinkAnalyzer linkAnalyzer) { //step 1: pre-allocate variable path segments PreAllocateAllPathSegmentsOnThePathFromThisToRoot(); //step 2: identify one-to-pne reachability paths IList <ReachabilityPath> identifiedOneToOneReachabilityPaths = IdentifyOneToOneReachabilityPath(); //step 3: identify one-to-many reachability paths IList <ReachabilityPath> identifiedOneToManyReachabilityPath = IdentifyOneToManyReachabilityPath(linkAnalyzer); //step 4: add all identified reachability paths foreach (ReachabilityPath reachabilityPath in identifiedOneToOneReachabilityPaths) { this.ReachabilityPaths.Add(reachabilityPath); } foreach (ReachabilityPath reachabilityPath in identifiedOneToManyReachabilityPath) { this.ReachabilityPaths.Add(reachabilityPath); } //step 5: reset pre-allocation this.Root.ResetAllocation(); }
public AnalysisResult AnalyzeSingleApi(string rawContent, string apiKey, string apiName, string versionKey, string versionName, string apiAdded, string versionAdded, ILinkAnalyzer linkAnalyzer) { OpenApiDiagnostic openApiDiagnostic = new OpenApiDiagnostic(); OpenApiDocument openApiDocument = null; try { //step 1: convert OpenAPI documentation into object model openApiDocument = new OpenApiStringReader().Read(rawContent, out openApiDiagnostic); } catch (Exception e) { // possibly IO Exception or Exception due to mal-formed OpenAPI documentation return(AnalysisResult.Create(apiKey, apiName, versionKey, versionName, apiAdded, versionAdded, null, 0, 0, false, e)); } //step 2: write diagnostic to log int openApiReaderErrors = 0; foreach (OpenApiError openApiError in openApiDiagnostic.Errors) { openApiReaderErrors++; //TODO: write to log } //step 3: create URI Model UriModel uriModel = null; try { uriModel = CustomizedUriModelFactory.Instance.Create(openApiDocument); } catch (Exception e) { return(AnalysisResult.Create(apiKey, apiName, versionKey, versionName, apiAdded, versionAdded, null, openApiReaderErrors, 0, false, e)); } //step 4: check whether URI Model contains variable path segments that have more than one path parameter bool hasUriModelVariablePathSegmentsWithMoreThanOnePathParameter = HasUriModelVariablePathSegmentsWithMoreThanOnePathParameter(uriModel); if (hasUriModelVariablePathSegmentsWithMoreThanOnePathParameter) { return(AnalysisResult.Create(apiKey, apiName, versionKey, versionName, apiAdded, versionAdded, uriModel, openApiReaderErrors, 0, true, null)); } //step 5: identify reachability paths int missingMediaCounter = 0; try { IList <PathSegment> pathSegmentsRepresentingResources = uriModel.Root.QuerySubTree.HasOperations().Results; for (int i = 0; i < pathSegmentsRepresentingResources.Count; i++) { ((CustomizedPathSegment)pathSegmentsRepresentingResources[i]).IdentifyReachabilityPaths(linkAnalyzer); Out.UpdateStatusBar(((double)i / (double)pathSegmentsRepresentingResources.Count) * 100); } missingMediaCounter = linkAnalyzer.MissingMediaCounter; } catch (Exception e) { //possibly Exception due to mal-formed OpenAPI documentation return(AnalysisResult.Create(apiKey, apiName, versionKey, versionName, apiAdded, versionAdded, uriModel, openApiReaderErrors, 0, hasUriModelVariablePathSegmentsWithMoreThanOnePathParameter, e)); } return(AnalysisResult.Create(apiKey, apiName, versionKey, versionName, apiAdded, versionAdded, uriModel, openApiReaderErrors, missingMediaCounter, hasUriModelVariablePathSegmentsWithMoreThanOnePathParameter, null)); }
/// <summary> /// Identifies and returns the list of one-to-many <see cref="ReachabilityPath"/>s /// </summary> /// <returns></returns> private IList <ReachabilityPath> IdentifyOneToManyReachabilityPath(ILinkAnalyzer linkAnalyzer) { IList <ReachabilityPath> reachabilityPaths = new List <ReachabilityPath>(); //step 1: load API Root PathSegment apiRoot = this.Root; //step 2: load all variable path segments of the URI Model (note that pre-allocated variable path segments are ignored) IList <PathSegment> variablePathSegments = apiRoot.QuerySubTree.IsVariable().Results; //step 3: prepare and identify list of variable path segments that are on the path between this path segment and the next descendants IList <PathSegment> variablePathSegmentsOnThePathBetweenThisPathSegmentAndNextDescendants = new List <PathSegment>(); foreach (PathSegment variablePathSegment in variablePathSegments) { //calculate path between API Root and the respective variable path segment //Note that for our case it does not matter, whether calculating the path between this path segment and the variable path segment //or the API Root and the variable path segment, since between API root and this path segment cannot be any variable path segment Stack <Node <string> > path = apiRoot.Path(variablePathSegment); //in the course of the next step, we will count the number of variable path segments being on the path between the API Root (or this path segment) and the respective variable path segment. int variablePathSegmentCounter = 0; while (path.Count > 0) { PathSegment pathSegment = (PathSegment)path.Pop(); if (pathSegment.IsVariable) { //increase counter for each found variable path segment variablePathSegmentCounter++; } } //if there is exactely one variable path segment (namely the variable path segment if (variablePathSegmentCounter == 1) { variablePathSegmentsOnThePathBetweenThisPathSegmentAndNextDescendants.Add(variablePathSegment); } } //step 4: iterate over the list of identified variable path segments foreach (PathSegment variablePathSegment in variablePathSegmentsOnThePathBetweenThisPathSegmentAndNextDescendants) { IList <Link> links = new List <Link>(); //iterate over all path parameters of the respective variable path segment foreach (PathParameter pathParameter in variablePathSegment.PathParameters) { //analyze response payload schemas IList <Link> linksToPathParameter = linkAnalyzer.AnalyzeResource(this, pathParameter); foreach (Link linkToPathParameter in linksToPathParameter) { links.Add(linkToPathParameter); } } //step 5: now we determine the target of the one-to-many reachability paths //if the respective variable path segment has operations (i.e. represents multiple resources)... if (variablePathSegment.HasOperations) { //...then it is the target ReachabilityPath reachabilityPath = new ReachabilityPath(this, variablePathSegment, ReachabilityPathType.oneToMany); foreach (Link link in links) { reachabilityPath.Links.Add(link); //activates the back reference (i.e. adds the link to the path parameter) link.ActivateBackReferenceToPathParameter(); } reachabilityPaths.Add(reachabilityPath); } //if the respective variable path segment HAS NOT any operation (i.e. DOES NOT represent multiple resources) else { //...then whe have to identify the next descendants of this variable path segment and set them as targets //Note that we want only next descendants that are NOT variable or whose path between the respective variable path segment and the next descendant //is not blocked by a variable path segment, since on the path from the source to the target can only be one variable path segment foreach (PathSegment nextDescendant in ((CustomizedPathSegment)variablePathSegment).NextDescendantsRepresentingResourcesButWithoutVariablePathSegments) { //...then the next descendant is one target ReachabilityPath reachabilityPath = new ReachabilityPath(this, nextDescendant, ReachabilityPathType.oneToMany); foreach (Link link in links) { reachabilityPath.Links.Add(link); //activates the back reference (i.e. adds the link to the path parameter) link.ActivateBackReferenceToPathParameter(); } reachabilityPaths.Add(reachabilityPath); } } } return(reachabilityPaths); }
public static void Main(string[] args) { //step 1: load arguments CustomizedArguments arguments = CustomizedArguments.Parse(args); //step 2: load log writer if (arguments.Has(CustomizedArguments.ARG_LOG_OUT)) { //console if (arguments.Get(CustomizedArguments.ARG_LOG_OUT).CompareTo(CustomizedArguments.OPT_LOG_OUT_CONSOLE) == 0) { Log.LogWriters.Add(new CustomizedConsoleLogWriter() { LogLevel = arguments.LogLevel }); } //file else { Log.LogWriters.Add(new FileLogWriter(arguments.LogPath + DateTime.Now.ToString(String.Format("yyyy-MM-dd_HH.mm.ss.FFF")) + ".log") { LogLevel = arguments.LogLevel }); } Log.Debug(TAG, "log_out:" + arguments.Get(CustomizedArguments.ARG_LOG_OUT)); } //default (console) else { Log.LogWriters.Add(new CustomizedConsoleLogWriter() { LogLevel = arguments.LogLevel }); } //step 3: load OpenAPI documentation Log.Info(TAG, "Load OpenAPI documentation from '" + arguments.Get(CustomizedArguments.ARG_SOURCE) + "'"); OpenApiDiagnostic openApiDiagnostic = new OpenApiDiagnostic(); OpenApiDocument openApiDocument = new OpenApiStringReader().Read(File.ReadAllText(arguments.Get(CustomizedArguments.ARG_SOURCE)), out openApiDiagnostic); foreach (OpenApiError openApiError in openApiDiagnostic.Errors) { Log.Error(TAG, "OpenAPI Reader Error: " + openApiError.Message); } Log.Info(TAG, "Load OpenAPI documentation - completed\n"); //step 4: create URI Model Log.Info(TAG, "Create URI Model:"); UriModel uriModel = CustomizedUriModelFactory.Instance.Create(openApiDocument); Log.Info(TAG, "\n" + uriModel.ToString() + "\n"); //step 5: identify reachability associations Log.Info(TAG, "Identify reachability associations:"); ILinkAnalyzer linkAnalyzer = LinkAnalyzerFactory.Create(); IList <PathSegment> pathSegmentsRepresentingResources = uriModel.Root.QuerySubTree.HasOperations().Results; foreach (PathSegment pathSegmentRepresentingResources in pathSegmentsRepresentingResources) { ((CustomizedPathSegment)pathSegmentRepresentingResources).IdentifyReachabilityPaths(linkAnalyzer); Log.Info(TAG, pathSegmentRepresentingResources.UriPath); foreach (ReachabilityPath association in ((CustomizedPathSegment)pathSegmentRepresentingResources).ReachabilityPaths) { Log.Info(TAG, association.ToString()); } } //step 6: set base path string basePath = ""; if (arguments.Has(CustomizedArguments.ARG_API_BASE_PATH)) { basePath = arguments.Get(CustomizedArguments.ARG_API_BASE_PATH); } else { foreach (OpenApiServer openApiServer in openApiDocument.Servers) { basePath = openApiServer.Url; } } Log.Info(TAG, "\nBase path of remote API: '" + basePath + "'"); //step 7: load property name prefix of injected properties string propertyNamePrefix = ""; if (arguments.Has(CustomizedArguments.ARG_INJECTION_PREFIX)) { propertyNamePrefix = arguments.Get(CustomizedArguments.ARG_INJECTION_PREFIX); } //step 8: prepare proxy IProxyHandler handler = new CustomizedProxyHandler(basePath, uriModel, propertyNamePrefix, arguments.Has(CustomizedArguments.ARG_EXTENDED_HYPERLINK), arguments.Has(CustomizedArguments.ARG_PREFLIGHT_HEAD_COUNTER)?Int32.Parse(arguments.Get(CustomizedArguments.ARG_PREFLIGHT_HEAD_COUNTER)):10); ApiRequest.IgnoreBadCertificates(); if (arguments.Has(CustomizedArguments.ARG_ACCESS_TOKEN)) { handler.UpdateAcessTokenAutomatically = false; handler.UpdateAuthorization(arguments.Get(CustomizedArguments.ARG_ACCESS_TOKEN)); Log.Info(TAG, "Access token has been loaded from arguments and will be injected into API requests automatically"); } else { handler.UpdateAcessTokenAutomatically = true; Log.Warning(TAG, "Access token is not specified in arguments. If the API expects an access token, make sure that the client specifies this token in each request."); } HttpController controller = new ProxyController(handler); //step 9: start proxy HttpService service = new DefaultHttpSysService(false, "+", Int32.Parse(arguments.Get(CustomizedArguments.ARG_PORT))); service.AddController(controller); Log.Info(TAG, "Proxy routes:"); Log.Info(TAG, service.Routes); service.Start(); Log.Info(TAG, "Proxy is listening on port '" + arguments.Get(CustomizedArguments.ARG_PORT) + "'"); Console.WriteLine("PRESS KEY TO TERMINATE SERVICE"); Console.ReadKey(); }