/// <summary> /// Render the factory /// </summary> public void Render(string ownerPackage, string apiNs, Feature f, System.IO.TextWriter tw) { ClassRenderer.s_imports.Clear(); // Validate arguments if (String.IsNullOrEmpty(ownerPackage)) { throw new ArgumentNullException("ownerPackage"); } if (String.IsNullOrEmpty(apiNs)) { throw new ArgumentNullException("apiNs"); } if (f == null || !(f is Class)) { throw new ArgumentException("Parameter must be of type Class", "f"); } // Create a local copy of the class Class cls = f as Class; StringWriter sw = new StringWriter(); tw.WriteLine("package {0}.{1};", ownerPackage, cls.ContainerName.ToLower()); #region Render Class Signature // Documentation if (DocumentationRenderer.Render(cls.Documentation, 0).Length == 0) { sw.WriteLine("\t/** No Summary Documentation Found */"); } else { sw.Write(DocumentationRenderer.Render(cls.Documentation, 0)); } // Create class signature sw.Write("public final class {0}Factory", Util.Util.PascalCase(cls.Name)); // If class is generic class string genericString = String.Empty; foreach (TypeParameter tp in cls.TypeParameters ?? new List <TypeParameter>()) { genericString += tp + ","; } if (!String.IsNullOrEmpty(genericString)) { genericString = String.Format("<{0}>", genericString.Substring(0, genericString.Length - 1)); // get rid of trailing , } sw.WriteLine("{"); #endregion sw.WriteLine("\tprivate {0}Factory() {{ super(); }}\r\n", Util.Util.PascalCase(cls.Name)); // Create newInstanceMethod sw.WriteLine("\tpublic static final {0} {1}Factory newInstance() {{", cls.TypeParameters != null && cls.TypeParameters.Count > 0 ? string.Format("<{0}>", genericString) : "", Util.Util.PascalCase(cls.Name)); sw.WriteLine("\t\treturn new {0}Factory{1}();", Util.Util.PascalCase(cls.Name), genericString); sw.WriteLine("\t}"); // Move to a factory // Is this an emtpy class that facilitates a choice? if (cls.SpecializedBy != null && cls.SpecializedBy.Count > 0 && cls.IsAbstract) { //// NB: In Java apparently super classes' static methods are acceessable //// in child classes which is different than .NET, so we're not going to cascade specializers foreach (TypeReference tr in cls.SpecializedBy) { if (tr.Class == null || tr.Class.ContainerName == "RIM" && !RimbaJavaRenderer.GenerateRim || tr.Class.IsAbstract) { continue; } Class child = tr.Class; // Create factory for the child Dictionary <String, String[]> ctors = ClassRenderer.CreateFactoryMethod(tr, "retVal", ownerPackage); // Write factory foreach (var kv in ctors) { string methodSignature = String.Format("{1}.{0}.{2}.create{3}", cls.ContainerName, ownerPackage, Util.Util.PascalCase(cls.Name), Util.Util.PascalCase(child.Name)), publicName = methodSignature; // Regex for extracting the parameter type rather than the type/name Regex parmRegex = new Regex(@"(([\w<>,.]*)\s(\w*)),?\s?"); MatchCollection parmMatches = parmRegex.Matches(kv.Value[0]); foreach (Match match in parmMatches) { methodSignature += match.Groups[1].Value.Substring(0, match.Groups[1].Value.IndexOf(" ")); } // JF: Added to protected against rendering the same factory method if (s_methodDeclarations.Contains(methodSignature)) { continue; } s_methodDeclarations.Add(methodSignature); // Render if there is even any content if (kv.Value[0].Length > 0) { string clsDoc = DocumentationRenderer.Render(child.Documentation, 1); string ctorClassName = String.Format("{0}.{2}.{1}", ownerPackage, tr.Class.Name, tr.Class.ContainerName.ToLower()); //// import already exists? //if(!s_imports.Exists(o=>o.EndsWith(Util.Util.PascalCase(tr.Class.Name)))) //{ // s_imports.Add(ctorClassName); // ctorClassName = ctorClassName.Substring(ctorClassName.LastIndexOf(".") + 1); //} //if (s_imports.Contains(ctorClassName)) // ctorClassName = ctorClassName.Substring(ctorClassName.LastIndexOf(".") + 1); if (clsDoc.Contains("*/")) { sw.Write(clsDoc.Substring(0, clsDoc.LastIndexOf("*/"))); } sw.WriteLine("* This function creates a new instance of {5}.{1}\r\n\t {4}\r\n\t*/\t\n\tpublic final {0} create{2}({3}) {{ ", ctorClassName, tr.Class.Name, Util.Util.PascalCase(child.Name), kv.Value[0].Substring(0, kv.Value[0].Length - 1), kv.Value[2], tr.Class.ContainerName.ToLower(), Util.Util.PascalCase(cls.Name) ); sw.WriteLine("\t\t{0} retVal = new {0}();", ctorClassName); sw.WriteLine("{0}", kv.Value[1]); sw.WriteLine("\t\treturn retVal;"); sw.WriteLine("\t}"); if (!factoryMethods.ContainsKey(tr.Name)) { factoryMethods.Add(tr.Name, new List <MohawkCollege.EHR.gpmr.Pipeline.Renderer.Java.Renderer.ClassRenderer.FactoryMethodInfo>()); } MohawkCollege.EHR.gpmr.Pipeline.Renderer.Java.Renderer.ClassRenderer.FactoryMethodInfo myInfo = new MohawkCollege.EHR.gpmr.Pipeline.Renderer.Java.Renderer.ClassRenderer.FactoryMethodInfo(publicName, kv.Value[2], methodSignature); //Match the regular expression below and capture its match into backreference number 1 «(([\w<>,]*?)\s(\w*),?\s?)» //Match the regular expression below and capture its match into backreference number 2 «([\w<>,]*?)» //Match a single character present in the list below «[\w<>,]*?» //Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?» //A word character (letters, digits, etc.) «\w» //One of the characters “<>,” «<>,» //Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.) «\s» //Match the regular expression below and capture its match into backreference number 3 «(\w*)» //Match a single character that is a “word character” (letters, digits, etc.) «\w*» //Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*» //Match the character “,” literally «,?» //Between zero and one times, as many times as possible, giving back as needed (greedy) «?» //Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.) «\s?» //Between zero and one times, as many times as possible, giving back as needed (greedy) «?» foreach (Match match in parmMatches) { myInfo.parameters.Add(match.Groups[1].Value); } // ADd the factory signature to the dictionary factoryMethods[tr.Name].Add(myInfo); } } } //#endregion } // End class sw.WriteLine("}"); #region Render the imports string[] apiImports = { "annotations.*", "datatypes.*", "datatypes.generic.*" }, jImports = { "java.lang.*", "java.util.*" }; foreach (var import in apiImports) { tw.WriteLine("import {0}.{1};", apiNs, import); } foreach (var import in jImports) { tw.WriteLine("import {0};", import); } foreach (var import in ClassRenderer.s_imports) { if (!import.EndsWith(String.Format(".{0}", Util.Util.PascalCase(f.Name)))) { tw.WriteLine("import {0};", import); } } tw.WriteLine(sw.ToString()); #endregion if (cls.ContainerName == "RIM" && String.Format("{0}.rim.{1}", ownerPackage, Util.Util.PascalCase(cls.Name)) != RimbaJavaRenderer.RootClass && !RimbaJavaRenderer.GenerateRim) { throw new NotSupportedException("RIM Elements will not be rendered"); } }
/// <summary> /// Render the factory /// </summary> public void Render(string ownerPackage, string apiNs, Feature f, System.IO.TextWriter tw) { ClassRenderer.s_imports.Clear(); // Validate arguments if (String.IsNullOrEmpty(ownerPackage)) throw new ArgumentNullException("ownerPackage"); if (String.IsNullOrEmpty(apiNs)) throw new ArgumentNullException("apiNs"); if (f == null || !(f is Class)) throw new ArgumentException("Parameter must be of type Class", "f"); // Create a local copy of the class Class cls = f as Class; StringWriter sw = new StringWriter(); tw.WriteLine("package {0}.{1};", ownerPackage, cls.ContainerName.ToLower()); #region Render Class Signature // Documentation if (DocumentationRenderer.Render(cls.Documentation, 0).Length == 0) sw.WriteLine("\t/** No Summary Documentation Found */"); else sw.Write(DocumentationRenderer.Render(cls.Documentation, 0)); // Create class signature sw.Write("public final class {0}Factory", Util.Util.PascalCase(cls.Name)); // If class is generic class string genericString = String.Empty; foreach (TypeParameter tp in cls.TypeParameters ?? new List<TypeParameter>()) genericString += tp + ","; if (!String.IsNullOrEmpty(genericString)) genericString = String.Format("<{0}>", genericString.Substring(0, genericString.Length - 1)); // get rid of trailing , sw.WriteLine("{"); #endregion sw.WriteLine("\tprivate {0}Factory() {{ super(); }}\r\n", Util.Util.PascalCase(cls.Name)); // Create newInstanceMethod sw.WriteLine("\tpublic static final {0} {1}Factory newInstance() {{", cls.TypeParameters != null && cls.TypeParameters.Count > 0 ? string.Format("<{0}>", genericString) : "", Util.Util.PascalCase(cls.Name)); sw.WriteLine("\t\treturn new {0}Factory{1}();", Util.Util.PascalCase(cls.Name), genericString); sw.WriteLine("\t}"); // Move to a factory // Is this an emtpy class that facilitates a choice? if (cls.SpecializedBy != null && cls.SpecializedBy.Count > 0 && cls.IsAbstract) { //// NB: In Java apparently super classes' static methods are acceessable //// in child classes which is different than .NET, so we're not going to cascade specializers foreach (TypeReference tr in cls.SpecializedBy) { if (tr.Class == null || tr.Class.ContainerName == "RIM" && !RimbaJavaRenderer.GenerateRim || tr.Class.IsAbstract) continue; Class child = tr.Class; // Create factory for the child Dictionary<String, String[]> ctors = ClassRenderer.CreateFactoryMethod(tr, "retVal", ownerPackage); // Write factory foreach (var kv in ctors) { string methodSignature = String.Format("{1}.{0}.{2}.create{3}", cls.ContainerName, ownerPackage, Util.Util.PascalCase(cls.Name), Util.Util.PascalCase(child.Name)), publicName = methodSignature; // Regex for extracting the parameter type rather than the type/name Regex parmRegex = new Regex(@"(([\w<>,.]*)\s(\w*)),?\s?"); MatchCollection parmMatches = parmRegex.Matches(kv.Value[0]); foreach (Match match in parmMatches) methodSignature += match.Groups[1].Value.Substring(0, match.Groups[1].Value.IndexOf(" ")); // JF: Added to protected against rendering the same factory method if (s_methodDeclarations.Contains(methodSignature)) continue; s_methodDeclarations.Add(methodSignature); // Render if there is even any content if (kv.Value[0].Length > 0) { string clsDoc = DocumentationRenderer.Render(child.Documentation, 1); string ctorClassName = String.Format("{0}.{2}.{1}", ownerPackage, tr.Class.Name, tr.Class.ContainerName.ToLower()); //// import already exists? //if(!s_imports.Exists(o=>o.EndsWith(Util.Util.PascalCase(tr.Class.Name)))) //{ // s_imports.Add(ctorClassName); // ctorClassName = ctorClassName.Substring(ctorClassName.LastIndexOf(".") + 1); //} //if (s_imports.Contains(ctorClassName)) // ctorClassName = ctorClassName.Substring(ctorClassName.LastIndexOf(".") + 1); if (clsDoc.Contains("*/")) sw.Write(clsDoc.Substring(0, clsDoc.LastIndexOf("*/"))); sw.WriteLine("* This function creates a new instance of {5}.{1}\r\n\t {4}\r\n\t*/\t\n\tpublic final {0} create{2}({3}) {{ ", ctorClassName, tr.Class.Name, Util.Util.PascalCase(child.Name), kv.Value[0].Substring(0, kv.Value[0].Length - 1), kv.Value[2], tr.Class.ContainerName.ToLower(), Util.Util.PascalCase(cls.Name) ); sw.WriteLine("\t\t{0} retVal = new {0}();", ctorClassName); sw.WriteLine("{0}", kv.Value[1]); sw.WriteLine("\t\treturn retVal;"); sw.WriteLine("\t}"); if (!factoryMethods.ContainsKey(tr.Name)) factoryMethods.Add(tr.Name, new List<MohawkCollege.EHR.gpmr.Pipeline.Renderer.Java.Renderer.ClassRenderer.FactoryMethodInfo>()); MohawkCollege.EHR.gpmr.Pipeline.Renderer.Java.Renderer.ClassRenderer.FactoryMethodInfo myInfo = new MohawkCollege.EHR.gpmr.Pipeline.Renderer.Java.Renderer.ClassRenderer.FactoryMethodInfo(publicName, kv.Value[2], methodSignature); //Match the regular expression below and capture its match into backreference number 1 «(([\w<>,]*?)\s(\w*),?\s?)» //Match the regular expression below and capture its match into backreference number 2 «([\w<>,]*?)» //Match a single character present in the list below «[\w<>,]*?» //Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?» //A word character (letters, digits, etc.) «\w» //One of the characters “<>,” «<>,» //Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.) «\s» //Match the regular expression below and capture its match into backreference number 3 «(\w*)» //Match a single character that is a “word character” (letters, digits, etc.) «\w*» //Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*» //Match the character “,” literally «,?» //Between zero and one times, as many times as possible, giving back as needed (greedy) «?» //Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.) «\s?» //Between zero and one times, as many times as possible, giving back as needed (greedy) «?» foreach (Match match in parmMatches) myInfo.parameters.Add(match.Groups[1].Value); // ADd the factory signature to the dictionary factoryMethods[tr.Name].Add(myInfo); } } } //#endregion } // End class sw.WriteLine("}"); #region Render the imports string[] apiImports = { "annotations.*", "datatypes.*", "datatypes.generic.*" }, jImports = { "java.lang.*", "java.util.*" }; foreach (var import in apiImports) tw.WriteLine("import {0}.{1};", apiNs, import); foreach (var import in jImports) tw.WriteLine("import {0};", import); foreach (var import in ClassRenderer.s_imports) { if (!import.EndsWith(String.Format(".{0}", Util.Util.PascalCase(f.Name)))) tw.WriteLine("import {0};", import); } tw.WriteLine(sw.ToString()); #endregion if (cls.ContainerName == "RIM" && String.Format("{0}.rim.{1}", ownerPackage, Util.Util.PascalCase(cls.Name)) != RimbaJavaRenderer.RootClass && !RimbaJavaRenderer.GenerateRim) throw new NotSupportedException("RIM Elements will not be rendered"); }