/// <summary> /// Optimize the <paramref name="feature"/> /// </summary> public MohawkCollege.EHR.gpmr.COR.Feature Optimize(MohawkCollege.EHR.gpmr.COR.Feature f, CombineLog workingLog) { string qualifiedName = String.Format("{0}.{1}", (f as Class).ContainerName, f.Name); // Garbage bin List <String> classGarbageBin = new List <string>(); List <ClassContent> contentGarbageBin = new List <ClassContent>(); // Still valid to process this feature if (!Repository.ContainsKey(qualifiedName)) { return(null); // Can't process non-existant class } // First determine if a class that is identical to this already exists FeatureComparer comparer = new FeatureComparer(); var matchingFeatures = from kv in Repository where comparer.Compare(kv.Value, f) == 0 select kv.Value; CombineInfo currentCombinationLog = new CombineInfo(); // Find matching features in each of the sub-systems if (matchingFeatures.Count() > 1 && CorCollapserPipelineTrigger.combine == true) { System.Diagnostics.Trace.WriteLine(String.Format("{0} other classes can be represented by this class", matchingFeatures.Count()), "debug"); currentCombinationLog.Destination = qualifiedName; foreach (var s in matchingFeatures) { string qName = String.Format("{0}.{1}", (s as Class).ContainerName, s.Name); if (qName != qualifiedName) { System.Diagnostics.Trace.WriteLine(String.Format("\tReplaces '{0}'", qName), "debug"); currentCombinationLog.Class.Add(qName); // Copy alternate traversal data foreach (ClassContent cc in (s as Class).Content) { if (cc is Property && (cc as Property).AlternateTraversalNames != null) { if (((f as Class).Content.Find(o => o.Name == cc.Name) as Property).AlternateTraversalNames == null) { ((f as Class).Content.Find(o => o.Name == cc.Name) as Property).AlternateTraversalNames = new List <Property.AlternateTraversalData>(); } ((f as Class).Content.Find(o => o.Name == cc.Name) as Property).AlternateTraversalNames.AddRange((cc as Property).AlternateTraversalNames); } } // Replace referneces ReplaceReferences(s as Class, f as Class); // Add an annotation f.Annotations.Add(new CodeCombineAnnotation((s as Class).CreateTypeReference())); // Remove this class (Add it to the garbage bin) classGarbageBin.Add(qName); } } workingLog.CombineOps.Add(currentCombinationLog); } // Now collapse members if (CorCollapserPipelineTrigger.collapse) { for (int i = 0; i < (f as Class).Content.Count; i++) { ClassContent cc = (f as Class).Content[i]; // Determine if it is a candidate for collapsing needless complexity if (IsCandidateForMeaninglessComplexityCollapse(cc)) { while (IsCandidateForMeaninglessComplexityCollapse(cc)) { System.Diagnostics.Trace.WriteLine(string.Format("\tCollapsing '{0}'", cc.Name), "debug"); CollapseMemberType(cc, f as Class); } } // Determine if it is a candidate for collapsing the entire type else if (IsCandidateForTypeCollapse(cc)) { System.Diagnostics.Trace.WriteLine(string.Format("\tCollapsing '{0}'", cc.Name), "debug"); CopyMembers((cc as Property).Type, f as Class, cc); contentGarbageBin.Add(cc); } } // Clean up garbage bin (f as Class).Content.RemoveAll(a => contentGarbageBin.Contains(a)); (f as Class).Content.Sort(new ClassContent.Comparator()); } // Clean the garbage bin foreach (string s in classGarbageBin) { Repository.Remove(s); } return(null); }
/// <summary> /// Fires when the host context has changed /// </summary> /// <param name="Context">The pipeline that is changing state</param> /// <param name="OldState">The old state</param> /// <param name="NewState">The new state</param> void hostContext_StateChanged(Pipeline Context, Pipeline.PipelineStates OldState, Pipeline.PipelineStates NewState) { switch (NewState) { case Pipeline.PipelineStates.SourceLoaded: Dictionary<String, StringCollection> parameters = hostContext.Data["CommandParameters"] as Dictionary<String, StringCollection>; StringCollection tCollection = null; if (parameters.TryGetValue("optimize", out tCollection)) enabled = Convert.ToBoolean(tCollection[0]); // Collection if (parameters.TryGetValue("collapse", out tCollection)) collapse = Convert.ToBoolean(tCollection[0]); // Combination if (parameters.TryGetValue("combine", out tCollection)) combine = Convert.ToBoolean(tCollection[0]); if (parameters.TryGetValue("collapse-ignore-fixed", out tCollection)) collapseIgnoreFixed = Convert.ToBoolean(tCollection[0]); if (parameters.TryGetValue("collapse-useless-name", out tCollection)) foreach(String s in tCollection) uselessWords.Add(s); if (parameters.TryGetValue("collapse-important-name", out tCollection)) foreach (String s in tCollection) importantWords.Add(s); if (parameters.TryGetValue("collapse-adv-naming", out tCollection)) collapseSpecialNaming = Convert.ToBoolean(tCollection[0]); if (parameters.TryGetValue("combine-replay", out tCollection)) logFile = tCollection[0]; // Collapse ignore if (!parameters.TryGetValue("collapse-ignore", out collapseIgnore) && collapse) throw new InvalidOperationException("If --collapse is specified, then the --collapse-ignore must be specified"); break; case Pipeline.PipelineStates.Compiled: if (!enabled) return; // Optimize the COR repository System.Diagnostics.Trace.WriteLine("Optimizing COR Repository...", "information"); ClassRepository classRep = hostContext.Data["SourceCR"] as ClassRepository; ClassRepositoryOptimizer optimizer = new ClassRepositoryOptimizer(); // Load the replay log if possible var combineLog = new CombineLog(); if (!String.IsNullOrEmpty(logFile) && File.Exists(logFile)) combineLog = CombineLog.Load(logFile); ClassRepository optimizedRepository = optimizer.Optimize(classRep, combineLog); // Save the replay log if (!String.IsNullOrEmpty(logFile)) combineLog.Save(logFile); System.Diagnostics.Trace.WriteLine(string.Format("Optimization resulted in {0:#,##0} fewer features ({1:#0}% reduction)", classRep.Count - optimizedRepository.Count, (1 - ((float)optimizedRepository.Count / classRep.Count)) * 100), "debug"); hostContext.Data["SourceCR"] = optimizedRepository; break; } }
/// <summary> /// Perform optimizations on <paramref name="source"/> /// </summary> /// <param name="source">The class repository to optimize</param> /// <returns>The optimized class repository</returns> public MohawkCollege.EHR.gpmr.COR.ClassRepository Optimize(MohawkCollege.EHR.gpmr.COR.ClassRepository source, CombineLog currentLog) { MohawkCollege.EHR.gpmr.COR.ClassRepository optimizedClassRepository = new MohawkCollege.EHR.gpmr.COR.ClassRepository(); // Copy to the optimized class library, two stop process because dictionaries are wierd // First pass, copy the destination stuff foreach (var featurePair in source) { if (currentLog.CombineOps.Exists(o => o.Destination == featurePair.Key)) { optimizedClassRepository.Add(featurePair.Key, featurePair.Value); // Attempt to fix a bug where the memberOf does not get updated on child content SetMemberOf(optimizedClassRepository[featurePair.Key], optimizedClassRepository); } } // Second pass, copy the collapsed stuff foreach (var featurePair in source) { if (!currentLog.CombineOps.Exists(o => o.Destination == featurePair.Key)) { optimizedClassRepository.Add(featurePair.Key, featurePair.Value); // Attempt to fix a bug where the memberOf does not get updated on child content SetMemberOf(optimizedClassRepository[featurePair.Key], optimizedClassRepository); } } currentLog.CombineOps.Clear(); // Scan for optimizers Dictionary<String, ICorOptimizer> optimizers = new Dictionary<string,ICorOptimizer>(); var optimizerTypes = from type in this.GetType().Assembly.GetTypes() where type.GetInterface("MohawkCollege.EHR.gpmr.Pipeline.Triggers.CorCollapser.ICorOptimizer") != null select type; // Add the optimizers foreach (var type in optimizerTypes) { ICorOptimizer optimizer = (ICorOptimizer)type.GetConstructor(Type.EmptyTypes).Invoke(null); optimizer.Repository = optimizedClassRepository; optimizers.Add(optimizer.HandlesType.ToString(), optimizer); } // Now process the class repository foreach (var featurePair in source) { ICorOptimizer handler = null; Feature f = null; if (optimizers.TryGetValue(featurePair.Value.GetType().ToString(), out handler) && optimizedClassRepository.TryGetValue(featurePair.Key, out f)) { System.Diagnostics.Trace.WriteLine(String.Format("Processing '{0}'...", featurePair.Key), "debug"); Feature optimizedFeature = handler.Optimize(optimizedClassRepository[featurePair.Key], currentLog); } else if(handler == null) System.Diagnostics.Trace.WriteLine(String.Format("Can't find handler for '{0}', no optimizations will be performed on '{1}'...", featurePair.Value.GetType().ToString(), featurePair.Key), "warn"); } // Get rid of empty sub-systems var subSystems = from subSys in source where subSys.Value is SubSystem select subSys.Value as SubSystem; foreach (var subSystem in subSystems) { SubSystem ss = optimizedClassRepository[subSystem.Name] as SubSystem; if (ss.OwnedClasses.Count == 0) { System.Diagnostics.Trace.WriteLine(String.Format("Removing empty sub-system '{0}'...", ss.Name), "error"); optimizedClassRepository.Remove(ss.Name); } } return optimizedClassRepository; }
/// <summary> /// Fires when the host context has changed /// </summary> /// <param name="Context">The pipeline that is changing state</param> /// <param name="OldState">The old state</param> /// <param name="NewState">The new state</param> void hostContext_StateChanged(Pipeline Context, Pipeline.PipelineStates OldState, Pipeline.PipelineStates NewState) { switch (NewState) { case Pipeline.PipelineStates.SourceLoaded: Dictionary <String, StringCollection> parameters = hostContext.Data["CommandParameters"] as Dictionary <String, StringCollection>; StringCollection tCollection = null; if (parameters.TryGetValue("optimize", out tCollection)) { enabled = Convert.ToBoolean(tCollection[0]); } // Collection if (parameters.TryGetValue("collapse", out tCollection)) { collapse = Convert.ToBoolean(tCollection[0]); } // Combination if (parameters.TryGetValue("combine", out tCollection)) { combine = Convert.ToBoolean(tCollection[0]); } if (parameters.TryGetValue("collapse-ignore-fixed", out tCollection)) { collapseIgnoreFixed = Convert.ToBoolean(tCollection[0]); } if (parameters.TryGetValue("collapse-useless-name", out tCollection)) { foreach (String s in tCollection) { uselessWords.Add(s); } } if (parameters.TryGetValue("collapse-important-name", out tCollection)) { foreach (String s in tCollection) { importantWords.Add(s); } } if (parameters.TryGetValue("collapse-adv-naming", out tCollection)) { collapseSpecialNaming = Convert.ToBoolean(tCollection[0]); } if (parameters.TryGetValue("combine-replay", out tCollection)) { logFile = tCollection[0]; } // Collapse ignore if (!parameters.TryGetValue("collapse-ignore", out collapseIgnore) && collapse) { throw new InvalidOperationException("If --collapse is specified, then the --collapse-ignore must be specified"); } break; case Pipeline.PipelineStates.Compiled: if (!enabled) { return; } // Optimize the COR repository System.Diagnostics.Trace.WriteLine("Optimizing COR Repository...", "information"); ClassRepository classRep = hostContext.Data["SourceCR"] as ClassRepository; ClassRepositoryOptimizer optimizer = new ClassRepositoryOptimizer(); // Load the replay log if possible var combineLog = new CombineLog(); if (!String.IsNullOrEmpty(logFile) && File.Exists(logFile)) { combineLog = CombineLog.Load(logFile); } ClassRepository optimizedRepository = optimizer.Optimize(classRep, combineLog); // Save the replay log if (!String.IsNullOrEmpty(logFile)) { combineLog.Save(logFile); } System.Diagnostics.Trace.WriteLine(string.Format("Optimization resulted in {0:#,##0} fewer features ({1:#0}% reduction)", classRep.Count - optimizedRepository.Count, (1 - ((float)optimizedRepository.Count / classRep.Count)) * 100), "debug"); hostContext.Data["SourceCR"] = optimizedRepository; break; } }
/// <summary> /// Perform optimizations on <paramref name="source"/> /// </summary> /// <param name="source">The class repository to optimize</param> /// <returns>The optimized class repository</returns> public MohawkCollege.EHR.gpmr.COR.ClassRepository Optimize(MohawkCollege.EHR.gpmr.COR.ClassRepository source, CombineLog currentLog) { MohawkCollege.EHR.gpmr.COR.ClassRepository optimizedClassRepository = new MohawkCollege.EHR.gpmr.COR.ClassRepository(); // Copy to the optimized class library, two stop process because dictionaries are wierd // First pass, copy the destination stuff foreach (var featurePair in source) { if (currentLog.CombineOps.Exists(o => o.Destination == featurePair.Key)) { optimizedClassRepository.Add(featurePair.Key, featurePair.Value); // Attempt to fix a bug where the memberOf does not get updated on child content SetMemberOf(optimizedClassRepository[featurePair.Key], optimizedClassRepository); } } // Second pass, copy the collapsed stuff foreach (var featurePair in source) { if (!currentLog.CombineOps.Exists(o => o.Destination == featurePair.Key)) { optimizedClassRepository.Add(featurePair.Key, featurePair.Value); // Attempt to fix a bug where the memberOf does not get updated on child content SetMemberOf(optimizedClassRepository[featurePair.Key], optimizedClassRepository); } } currentLog.CombineOps.Clear(); // Scan for optimizers Dictionary <String, ICorOptimizer> optimizers = new Dictionary <string, ICorOptimizer>(); var optimizerTypes = from type in this.GetType().Assembly.GetTypes() where type.GetInterface("MohawkCollege.EHR.gpmr.Pipeline.Triggers.CorCollapser.ICorOptimizer") != null select type; // Add the optimizers foreach (var type in optimizerTypes) { ICorOptimizer optimizer = (ICorOptimizer)type.GetConstructor(Type.EmptyTypes).Invoke(null); optimizer.Repository = optimizedClassRepository; optimizers.Add(optimizer.HandlesType.ToString(), optimizer); } // Now process the class repository foreach (var featurePair in source) { ICorOptimizer handler = null; Feature f = null; if (optimizers.TryGetValue(featurePair.Value.GetType().ToString(), out handler) && optimizedClassRepository.TryGetValue(featurePair.Key, out f)) { System.Diagnostics.Trace.WriteLine(String.Format("Processing '{0}'...", featurePair.Key), "debug"); Feature optimizedFeature = handler.Optimize(optimizedClassRepository[featurePair.Key], currentLog); } else if (handler == null) { System.Diagnostics.Trace.WriteLine(String.Format("Can't find handler for '{0}', no optimizations will be performed on '{1}'...", featurePair.Value.GetType().ToString(), featurePair.Key), "warn"); } } // Get rid of empty sub-systems var subSystems = from subSys in source where subSys.Value is SubSystem select subSys.Value as SubSystem; foreach (var subSystem in subSystems) { SubSystem ss = optimizedClassRepository[subSystem.Name] as SubSystem; if (ss.OwnedClasses.Count == 0) { System.Diagnostics.Trace.WriteLine(String.Format("Removing empty sub-system '{0}'...", ss.Name), "error"); optimizedClassRepository.Remove(ss.Name); } } return(optimizedClassRepository); }
/// <summary> /// Optimize the <paramref name="feature"/> /// </summary> public MohawkCollege.EHR.gpmr.COR.Feature Optimize(MohawkCollege.EHR.gpmr.COR.Feature f, CombineLog workingLog) { string qualifiedName = String.Format("{0}.{1}", (f as Class).ContainerName, f.Name); // Garbage bin List<String> classGarbageBin = new List<string>(); List<ClassContent> contentGarbageBin = new List<ClassContent>(); // Still valid to process this feature if (!Repository.ContainsKey(qualifiedName)) return null; // Can't process non-existant class // First determine if a class that is identical to this already exists FeatureComparer comparer = new FeatureComparer(); var matchingFeatures = from kv in Repository where comparer.Compare(kv.Value, f) == 0 select kv.Value; CombineInfo currentCombinationLog = new CombineInfo(); // Find matching features in each of the sub-systems if (matchingFeatures.Count() > 1 && CorCollapserPipelineTrigger.combine == true) { System.Diagnostics.Trace.WriteLine(String.Format("{0} other classes can be represented by this class", matchingFeatures.Count()), "debug"); currentCombinationLog.Destination = qualifiedName; foreach (var s in matchingFeatures) { string qName = String.Format("{0}.{1}", (s as Class).ContainerName, s.Name); if (qName != qualifiedName) { System.Diagnostics.Trace.WriteLine(String.Format("\tReplaces '{0}'", qName), "debug"); currentCombinationLog.Class.Add(qName); // Copy alternate traversal data foreach (ClassContent cc in (s as Class).Content) if (cc is Property && (cc as Property).AlternateTraversalNames != null) { if (((f as Class).Content.Find(o => o.Name == cc.Name) as Property).AlternateTraversalNames == null) ((f as Class).Content.Find(o => o.Name == cc.Name) as Property).AlternateTraversalNames = new List<Property.AlternateTraversalData>(); ((f as Class).Content.Find(o => o.Name == cc.Name) as Property).AlternateTraversalNames.AddRange((cc as Property).AlternateTraversalNames); } // Replace referneces ReplaceReferences(s as Class, f as Class); // Add an annotation f.Annotations.Add(new CodeCombineAnnotation((s as Class).CreateTypeReference())); // Remove this class (Add it to the garbage bin) classGarbageBin.Add(qName); } } workingLog.CombineOps.Add(currentCombinationLog); } // Now collapse members if (CorCollapserPipelineTrigger.collapse) { for(int i = 0; i < (f as Class).Content.Count; i++) { ClassContent cc = (f as Class).Content[i]; // Determine if it is a candidate for collapsing needless complexity if (IsCandidateForMeaninglessComplexityCollapse(cc)) { while (IsCandidateForMeaninglessComplexityCollapse(cc)) { System.Diagnostics.Trace.WriteLine(string.Format("\tCollapsing '{0}'", cc.Name), "debug"); CollapseMemberType(cc, f as Class); } } // Determine if it is a candidate for collapsing the entire type else if (IsCandidateForTypeCollapse(cc)) { System.Diagnostics.Trace.WriteLine(string.Format("\tCollapsing '{0}'", cc.Name), "debug"); CopyMembers((cc as Property).Type, f as Class, cc); contentGarbageBin.Add(cc); } } // Clean up garbage bin (f as Class).Content.RemoveAll(a => contentGarbageBin.Contains(a)); (f as Class).Content.Sort(new ClassContent.Comparator()); } // Clean the garbage bin foreach (string s in classGarbageBin) Repository.Remove(s); return null; }