Esempio n. 1
0
        /// <summary>
        /// Parses the given command-line arguments.
        /// </summary>
        /// <param name="args">Arguments to be parsed.</param>
        /// <returns>An instance of Args containing the argument values; null if the argument list is invalid.</returns>
        internal static Args Parse(string[] args)
        {
            //
            // Valid argument count, length and prefixes?
            //
            if (!CheckArgs(args))
            {
                return(null);
            }

            Args res = new Args();

            //
            // Url shouldn't be empty and should start with either http:// or https://.
            //
            string url = FindArg(args, "url");

            if (url == null || url.Length == 0)
            {
                return(null);
            }
            res.Url = url;
            url     = url.ToLower();
            if (!(url.StartsWith("http://") && url.Length > 7) && !(url.StartsWith("https://") && url.Length > 8))
            {
                return(null);
            }

            //
            // List shouldn't be empty.
            //
            string list = FindArg(args, "list");

            if (list == null || list.Length == 0)
            {
                return(null);
            }
            res.List = list;

            //
            // Output language can be set optionally and should be CS or VB (case-insensitive).
            //
            string language = FindArg(args, "language");

            if (language != null && language.Length != 0)
            {
                language = language.ToUpper();

                if (language != "CS" && language != "VB")
                {
                    return(null);
                }
                else
                {
                    res.Language = language;
                }
            }
            else
            {
                res.Language = "CS";
            }

            //
            // Out can optionally be empty; in that case, take the lists's name suffixed with the language extension.
            //
            string file = FindArg(args, "out");

            if (file == null || file.Length == 0)
            {
                file = list + (res.Language == "CS" ? ".cs" : ".vb");
                foreach (char c in Path.GetInvalidFileNameChars())
                {
                    file = file.Replace(c.ToString(), "");
                }
            }
            res.File = file;

            //
            // Only process authentication arguments if a user argument is present.
            //
            string user = FindArg(args, "user");

            if (user != null && user.Length != 0)
            {
                //
                // Password required if user has been specified. Password can be the empty string.
                //
                string password = FindArg(args, "password");
                if (password != null)
                {
                    res.User     = user;
                    res.Password = password;

                    //
                    // Optional domain name.
                    //
                    string domain = FindArg(args, "domain");
                    if (domain != null && domain.Length != 0)
                    {
                        res.Domain = domain;
                    }
                }
                else
                {
                    return(null);
                }
            }

            return(res);
        }
Esempio n. 2
0
        /// <summary>
        /// Generates an entity based on the given arguments.
        /// </summary>
        /// <param name="a">Arguments specifying the list to be exported.</param>
        /// <returns>Entity object containing the code and other information about the exported entity; null if the export wasn't successful.</returns>
        public Entity Generate(Args a)
        {
            //
            // Set correct language code fragments.
            //
            if ((language = a.Language) == "CS")
            {
                ENUM             = ENUM_CS;
                CLASS            = CLASS_CS;
                PROP             = PROP_CS;
                PROP_READONLY    = PROP_READONLY_CS;
                CHOICEHELPERPROP = CHOICEHELPERPROP_CS;
            }
            else
            {
                ENUM             = ENUM_VB;
                CLASS            = CLASS_VB;
                PROP             = PROP_VB;
                PROP_READONLY    = PROP_READONLY_VB;
                CHOICEHELPERPROP = CHOICEHELPERPROP_VB;
            }

            //
            // List definition XML; will be downloaded from server.
            //
            XmlNode lst;

            //
            // Create proxy object referring to the SharePoint lists.asmx service on the specified server.
            //
            Lists l = new Lists();

            l.Url = a.Url.TrimEnd('/') + "/_vti_bin/lists.asmx";

            //
            // Try to connect to server.
            //
            try
            {
                //
                // Send event about connection.
                //
                EventHandler <ConnectingEventArgs> connecting = Connecting;
                if (connecting != null)
                {
                    connecting(this, new ConnectingEventArgs(l.Url));
                }

                //
                // Integrated authentication using current network credentials.
                //
                if (a.User == null)
                {
                    l.Credentials = CredentialCache.DefaultNetworkCredentials;
                }
                //
                // Use specified credentials.
                //
                else
                {
                    if (a.Domain == null)
                    {
                        l.Credentials = new NetworkCredential(a.User, a.Password);
                    }
                    else
                    {
                        l.Credentials = new NetworkCredential(a.User, a.Password, a.Domain);
                    }
                }

                //
                // Send event about connection completion.
                //
                EventHandler <ConnectedEventArgs> connected = Connected;
                if (connected != null)
                {
                    connected(this, new ConnectedEventArgs());
                }
            }
            catch (Exception ex)
            {
                //
                // Send event about connection failure.
                //
                EventHandler <ConnectedEventArgs> connected = Connected;
                if (connected != null)
                {
                    connected(this, new ConnectedEventArgs(ex));
                }

                return(null);
            }

            try
            {
                //
                // Load schema from server using lists.asmx web service and send event about schema loading.
                //
                EventHandler <LoadingSchemaEventArgs> loadingSchema = LoadingSchema;
                if (loadingSchema != null)
                {
                    loadingSchema(this, new LoadingSchemaEventArgs(a.List));
                }
                lst = l.GetList(a.List);

                //
                // Send event about schema loading completion.
                //
                EventHandler <LoadedSchemaEventArgs> loadedSchema = LoadedSchema;
                if (loadedSchema != null)
                {
                    loadedSchema(this, new LoadedSchemaEventArgs());
                }
            }
            catch (Exception ex)
            {
                //
                // Send event about schema loading failure.
                //
                EventHandler <LoadedSchemaEventArgs> loadedSchema = LoadedSchema;
                if (loadedSchema != null)
                {
                    loadedSchema(this, new LoadedSchemaEventArgs(ex));
                }

                return(null);
            }

            //
            // Get general information of the list.
            //
            string listName        = GetFriendlyName((string)lst.Attributes["Title"].Value);
            string listDescription = (string)lst.Attributes["Description"].Value;

            if (listDescription == "")
            {
                listDescription = null;
            }
            Guid   listID  = new Guid((string)lst.Attributes["ID"].Value);
            int    version = int.Parse(lst.Attributes["Version"].Value);
            string path    = (string)lst.Attributes["RootFolder"].Value;

            //
            // Send event about schema exporting.
            //
            EventHandler <ExportingSchemaEventArgs> exportingSchema = ExportingSchema;

            if (exportingSchema != null)
            {
                exportingSchema(this, new ExportingSchemaEventArgs(listName, listID, version));
            }

            //
            // Get fields.
            //
            XmlElement    fields = lst["Fields"];
            StringBuilder props  = new StringBuilder();
            int           n      = 0;

            foreach (XmlNode c in fields.ChildNodes)
            {
                //
                // Field ID (GUID).
                //
                XmlAttribute aID = c.Attributes["ID"];
                string       id  = "";
                if (aID != null)
                {
                    id = new Guid(aID.Value).ToString();
                }

                //
                // Field name.
                //
                string name        = (string)c.Attributes["Name"].Value;
                string displayName = (string)c.Attributes["DisplayName"].Value;

                //
                // Field description.
                //
                XmlAttribute aDescription = c.Attributes["Description"];
                string       description  = null;
                if (aDescription != null)
                {
                    description = (string)aDescription.Value;
                }

                //
                // Field hidden?
                //
                XmlAttribute aHidden = c.Attributes["Hidden"];
                bool         hidden  = false;
                if (aHidden != null)
                {
                    hidden = bool.Parse(aHidden.Value);
                }

                //
                // Field read-only?
                //
                XmlAttribute aReadOnly = c.Attributes["ReadOnly"];
                bool         readOnly  = false;
                if (aReadOnly != null)
                {
                    readOnly = bool.Parse(aReadOnly.Value);
                }

                //
                // Field type.
                //
                string type = (string)c.Attributes["Type"].Value;
                bool   calc = false;

                //
                // Calculated field. Use underlying type for mapping.
                //
                if (type == "Calculated")
                {
                    type = (string)c.Attributes["ResultType"].Value;
                    calc = true;
                }

                //
                // Primary key field should be imported as well.
                //
                XmlAttribute primaryKey = c.Attributes["PrimaryKey"];
                bool         pk         = false;
                if (primaryKey != null)
                {
                    pk = bool.Parse(primaryKey.Value);
                }

                //
                // Export only fields that aren't hidden or the primary key field.
                //
                if (!hidden || pk)
                {
                    //
                    // Get underlying .NET type textual name for C# class generation.
                    // Additional field might be required for multi-choice fields with fill-in choice.
                    //
                    bool   additional;
                    string bclType = GetType(c, out additional);

                    //
                    // Is the underlying type recognized and supported by the mapper?
                    //
                    if (bclType != null)
                    {
                        //
                        // Read-only and calculated field require additional mapping attribute parameters.
                        //
                        StringBuilder extra = new StringBuilder();
                        if (pk)
                        {
                            extra.AppendFormat(", PrimaryKey{0}true", language == "CS" ? " = " : ":=");
                        }
                        if (readOnly)
                        {
                            extra.AppendFormat(", ReadOnly{0}true", language == "CS" ? " = " : ":=");
                        }
                        if (calc)
                        {
                            extra.AppendFormat(", Calculated{0}true", language == "CS" ? " = " : ":=");
                        }

                        //
                        // Create helper field and refer to it in case a multi-choice fields with fill-in choice was detected.
                        // The helper field has the same name as the .NET type (which will be an enum) suffixed with "Other".
                        //
                        string helper = null;
                        if (additional)
                        {
                            helper = GetFriendlyName((string)c.Attributes["DisplayName"].Value) + "Other";
                            extra.AppendFormat(", OtherChoice{1}\"{0}\"", helper, language == "CS" ? " = " : ":=");
                        }

                        //
                        // Lookup fields require a LookupField attribute property to be set.
                        //
                        if ((string)c.Attributes["Type"].Value == "Lookup" ||
                            (string)c.Attributes["Type"].Value == "LookupMulti")
                        {
                            extra.AppendFormat(", LookupField{1}\"{0}\"", (string)c.Attributes["ShowField"].Value, language == "CS" ? " = " : ":=");
                        }

                        //
                        // LookupMulti fields shouldn't be settable. The underlying IList<T> type will allow changes to the collection though.
                        //
                        if ((string)c.Attributes["Type"].Value == "LookupMulti")
                        {
                            readOnly = true;
                        }

                        //
                        // Generate a property for the current field and append it to the properties output string.
                        //
                        props.AppendFormat((readOnly ? PROP_READONLY : PROP), (description ?? displayName), bclType, GetFriendlyName(displayName), XmlConvert.DecodeName(name), type, id, extra.ToString());

                        //
                        // Generate additional helper property if needed.
                        //
                        if (additional)
                        {
                            props.AppendFormat(CHOICEHELPERPROP, displayName, helper, XmlConvert.DecodeName(name), id);
                        }

                        //
                        // Keep field count.
                        //
                        n++;
                    }
                }
            }

            //
            // Send event about schema exporting completion.
            //
            EventHandler <ExportedSchemaEventArgs> exportedSchema = ExportedSchema;

            if (exportedSchema != null)
            {
                exportedSchema(this, new ExportedSchemaEventArgs(n));
            }

            //
            // Build code with class definition containing the properties and the helper enums.
            //
            StringBuilder output = new StringBuilder();

            output.AppendFormat(CLASS, listName, props.ToString(), listName, listID.ToString(), version, (listDescription ?? listName), path);

            //
            // Return entity.
            //
            Entity entity = new Entity();

            entity.Name    = listName;
            entity.Id      = listID;
            entity.Code    = output.ToString();
            entity.Lookups = lookups;
            return(entity);
        }
Esempio n. 3
0
        /// <summary>
        /// Entry point for SpMetal.
        /// </summary>
        /// <param name="args">Command-line arguments.</param>
        static void Main(string[] args)
        {
            //
            // Title including assembly version number.
            //
            Console.WriteLine("Bart De Smet SpMetal SharePoint List Definition Export version {0}", Assembly.GetEntryAssembly().GetName().Version);
            Console.WriteLine("Copyright (C) Bart De Smet 2007. All rights reserved.\n");

            //
            // Parse arguments.
            //
            Args a = Args.Parse(args);

            //
            // Invalid arguments: display help information and exit.
            //
            if (a == null)
            {
                Console.WriteLine("No inputs specified\n");

                string file = Assembly.GetEntryAssembly().GetName().Name + ".exe";
                Console.WriteLine("Usage: {0} -url:<url> -list:<list> [-out:<file>] [-language:<language>]", file);
                Console.WriteLine("       {0} [-user:<user> -password:<password> [-domain:<domain>]]", new string(' ', file.Length));
                Console.WriteLine();

                Console.WriteLine("  -url:<url>            URL to the root of the SharePoint site");
                Console.WriteLine("  -list:<list>          Name of the list");
                Console.WriteLine("  -out:<file>           Output file");
                Console.WriteLine("  -language:<language>  Code language used for output (VB or CS)");
                Console.WriteLine("                        (Default: CS)");
                Console.WriteLine();

                Console.WriteLine("  -user:<user>          User name for connection to SharePoint site");
                Console.WriteLine("  -password:<password>  Password for connection to SharePoint site");
                Console.WriteLine("  -domain:<domain>      Domain for connection to SharePoint site");

                return;
            }

            //
            // Set correct language code fragments.
            //
            if ((language = a.Language) == "CS")
            {
                ENUM             = ENUM_CS;
                CLASS            = CLASS_CS;
                PROP             = PROP_CS;
                CHOICEHELPERPROP = CHOICEHELPERPROP_CS;
            }
            else
            {
                ENUM             = ENUM_VB;
                CLASS            = CLASS_VB;
                PROP             = PROP_VB;
                CHOICEHELPERPROP = CHOICEHELPERPROP_VB;
            }

            //
            // List definition XML; will be downloaded from server.
            //
            XmlNode lst;

            //
            // Try to connect to server.
            //
            try
            {
                Console.Write("Connecting to server... ");

                //
                // Create proxy object referring to the SharePoint lists.asmx service on the specified server.
                //
                Lists l = new Lists();
                l.Url = a.Url.TrimEnd('/') + "/_vti_bin/lists.asmx";

                //
                // Integrated authentication using current network credentials.
                //
                if (a.User == null)
                {
                    l.Credentials = CredentialCache.DefaultNetworkCredentials;
                }
                //
                // Use specified credentials.
                //
                else
                {
                    if (a.Domain == null)
                    {
                        l.Credentials = new NetworkCredential(a.User, a.Password);
                    }
                    else
                    {
                        l.Credentials = new NetworkCredential(a.User, a.Password, a.Domain);
                    }
                }

                Console.WriteLine("Done");

                //
                // Load schema from server using lists.asmx web service.
                //
                Console.Write("Loading schema... ");
                lst = l.GetList(a.List);

                Console.WriteLine("Done\n");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed\n");
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex.Message);
                Console.ResetColor();
                Environment.Exit(-1);
                return;
            }

            //
            // Get general information of the list.
            //
            string listName        = GetFriendlyName((string)lst.Attributes["Title"].Value);
            string listDescription = (string)lst.Attributes["Description"].Value;

            if (listDescription == "")
            {
                listDescription = null;
            }
            Guid   listID  = new Guid((string)lst.Attributes["ID"].Value);
            int    version = int.Parse(lst.Attributes["Version"].Value);
            string path    = (string)lst.Attributes["RootFolder"].Value;

            Console.Write("Processing list {0} ({1}) version {2}... ", listName, listID, version);

            //
            // Get fields.
            //
            XmlElement    fields = lst["Fields"];
            StringBuilder props  = new StringBuilder();
            int           n      = 0;

            foreach (XmlNode c in fields.ChildNodes)
            {
                //
                // Field ID (GUID).
                //
                XmlAttribute aID = c.Attributes["ID"];
                string       id  = "";
                if (aID != null)
                {
                    id = new Guid(aID.Value).ToString();
                }

                //
                // Field name.
                //
                string name        = (string)c.Attributes["Name"].Value;
                string displayName = (string)c.Attributes["DisplayName"].Value;

                //
                // Field description.
                //
                XmlAttribute aDescription = c.Attributes["Description"];
                string       description  = null;
                if (aDescription != null)
                {
                    description = (string)aDescription.Value;
                }

                //
                // Field hidden?
                //
                XmlAttribute aHidden = c.Attributes["Hidden"];
                bool         hidden  = false;
                if (aHidden != null)
                {
                    hidden = bool.Parse(aHidden.Value);
                }

                //
                // Field read-only?
                //
                XmlAttribute aReadOnly = c.Attributes["ReadOnly"];
                bool         readOnly  = false;
                if (aReadOnly != null)
                {
                    readOnly = bool.Parse(aReadOnly.Value);
                }

                //
                // Field type.
                //
                string type = (string)c.Attributes["Type"].Value;
                bool   calc = false;

                //
                // Calculated field. Use underlying type for mapping.
                //
                if (type == "Calculated")
                {
                    type = (string)c.Attributes["ResultType"].Value;
                    calc = true;
                }

                //
                // Field inherited from base type?
                //
                XmlAttribute aFromBaseType = c.Attributes["FromBaseType"];
                bool         fromBaseType  = false;
                if (aFromBaseType != null)
                {
                    fromBaseType = bool.Parse(aFromBaseType.Value);
                }

                //
                // Export only field that aren't hidden and aren't inherited from the base type.
                //
                if (!hidden && !fromBaseType)
                {
                    //
                    // Get underlying .NET type textual name for C# class generation.
                    // Additional field might be required for multi-choice fields with fill-in choice.
                    //
                    bool   additional;
                    string bclType = GetType(c, out additional);

                    //
                    // Is the underlying type recognized and supported by the mapper?
                    //
                    if (bclType != null)
                    {
                        //
                        // Read-only and calculated field require additional mapping attribute parameters.
                        //
                        StringBuilder extra = new StringBuilder();
                        if (readOnly)
                        {
                            extra.AppendFormat(", ReadOnly{0}true", language == "CS" ? " = " : ":=");
                        }
                        if (calc)
                        {
                            extra.AppendFormat(", Calculated{0}true", language == "CS" ? " = " : ":=");
                        }

                        //
                        // Create helper field and refer to it in case a multi-choice fields with fill-in choice was detected.
                        // The helper field has the same name as the .NET type (which will be an enum) suffixed with "Other".
                        //
                        string helper = null;
                        if (additional)
                        {
                            helper = GetFriendlyName((string)c.Attributes["DisplayName"].Value) + "Other";
                            extra.AppendFormat(", OtherChoice{1}\"{0}\"", helper, language == "CS" ? " = " : ":=");
                        }

                        //
                        // Generate a property for the current field and append it to the properties output string.
                        //
                        props.AppendFormat(PROP, (description ?? displayName), bclType, GetFriendlyName(displayName), XmlConvert.DecodeName(name), type, id, extra.ToString());

                        //
                        // Generate additional helper property if needed.
                        //
                        if (additional)
                        {
                            props.AppendFormat(CHOICEHELPERPROP, displayName, helper, XmlConvert.DecodeName(name), id);
                        }

                        //
                        // Keep field count.
                        //
                        n++;
                    }
                }
            }

            //
            // Print statistical information.
            //
            Console.WriteLine("Done");
            Console.WriteLine("Exported {0} properties and {1} helper enums", n, enums.Count);
            Console.WriteLine();

            //
            // Build file with class definition containing the properties and the helper enums.
            //
            Console.Write("Writing file {0}... ", a.File);
            StringBuilder output = new StringBuilder();

            output.AppendFormat(CLASS, listName, props.ToString(), listName, listID.ToString(), version, (listDescription ?? listName), path);

            foreach (string e in enums)
            {
                output.Append(e);
            }

            //
            // Write to output file.
            //
            using (StreamWriter sw = File.CreateText(a.File))
            {
                sw.WriteLine(output.ToString());
                Console.WriteLine("Done");
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Entry point for SpMetal.
        /// </summary>
        /// <param name="args">Command-line arguments.</param>
        static void Main(string[] args)
        {
            //
            // Title including assembly version number.
            //
            Console.WriteLine("Bart De Smet SpMetal SharePoint List Definition Export version {0}", Assembly.GetEntryAssembly().GetName().Version);
            Console.WriteLine("Copyright (C) Bart De Smet 2007. All rights reserved.\n");

            //
            // Parse arguments.
            //
            Args a = Args.Parse(args);

            //
            // Invalid arguments: display help information and exit.
            //
            if (a == null)
            {
                Console.WriteLine("No inputs specified\n");

                string file = Assembly.GetEntryAssembly().GetName().Name + ".exe";
                Console.WriteLine("Usage: {0} -url:<url> -list:<list> [-out:<file>] [-language:<language>]", file);
                Console.WriteLine("       {0} [-user:<user> -password:<password> [-domain:<domain>]]", new string(' ', file.Length));
                Console.WriteLine();

                Console.WriteLine("  -url:<url>            URL to the root of the SharePoint site");
                Console.WriteLine("  -list:<list>          Name of the list");
                Console.WriteLine("  -out:<file>           Output file");
                Console.WriteLine("  -language:<language>  Code language used for output (VB or CS)");
                Console.WriteLine("                        (Default: CS)");
                Console.WriteLine();

                Console.WriteLine("  -user:<user>          User name for connection to SharePoint site");
                Console.WriteLine("  -password:<password>  Password for connection to SharePoint site");
                Console.WriteLine("  -domain:<domain>      Domain for connection to SharePoint site");

                return;
            }

            //
            // Entity generator.
            //
            EntityGenerator gen = new EntityGenerator();

            gen.Connecting += delegate(object sender, ConnectingEventArgs e) { Console.Write("Connecting to server... "); };
            gen.Connected  += delegate(object sender, ConnectedEventArgs e)
            {
                if (e.Succeeded)
                {
                    Console.WriteLine("Done");
                }
                else
                {
                    Console.WriteLine("Failed\n");
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(e.Exception.Message);
                    Console.ResetColor();
                    Environment.Exit(-1);
                }
            };
            gen.LoadingSchema += delegate(object sender, LoadingSchemaEventArgs e) { Console.Write("Loading schema... "); };
            gen.LoadedSchema  += delegate(object sender, LoadedSchemaEventArgs e)
            {
                if (e.Succeeded)
                {
                    Console.WriteLine("Done\n");
                }
                else
                {
                    Console.WriteLine("Failed\n");
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(e.Exception.Message);
                    Console.ResetColor();
                    Environment.Exit(-1);
                }
            };
            gen.ExportingSchema += delegate(object sender, ExportingSchemaEventArgs e) { Console.Write("Processing list {0} ({1}) version {2}... ", e.List, e.Identifier, e.Version); };
            gen.ExportedSchema  += delegate(object sender, ExportedSchemaEventArgs e)
            {
                if (e.Succeeded)
                {
                    Console.WriteLine("Done");
                    Console.WriteLine("Exported {0} properties\n", e.PropertyCount);
                }
                else
                {
                    Console.WriteLine("Failed\n");
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(e.Exception.Message);
                    Console.ResetColor();
                    Environment.Exit(-1);
                }
            };

            //
            // Create a queue of entities that allows to process Lookup field entities.
            //
            Queue <Entity>            entities            = new Queue <Entity>();
            HashSet <string>          encounteredEntities = new HashSet <string>();
            Dictionary <Guid, string> map = new Dictionary <Guid, string>();

            //
            // Generate the requested entity.
            //
            HashSet <string> forbiddenTypeNames = new HashSet <string>();
            Entity           entity             = gen.Generate(a);

            //
            // Infer file name from list name if not specified on the command-line (v0.2.0.0).
            //
            if (a.File == null || a.File.Length == 0)
            {
                string file = entity.Name + (a.Language == "CS" ? ".cs" : ".vb");
                foreach (char c in Path.GetInvalidFileNameChars())
                {
                    file = file.Replace(c.ToString(), "");
                }
                a.File = file;
            }

            //
            // Build the code; import the namespaces required.
            //
            StringBuilder allCode = new StringBuilder();

            if (a.Language == "CS")
            {
                allCode.Append(IMPORTS_CS);
            }
            else
            {
                allCode.Append(IMPORTS_VB);
            }

            //
            // Resolve all Lookup field references, recursively.
            //
            entities.Enqueue(entity);
            map.Add(entity.Id, entity.Name); //Patch for lists that reference themselves. No need to re-generate entity type.
            encounteredEntities.Add(entity.Name);
            while (entities.Count > 0)
            {
                entity = entities.Dequeue();

                //
                // Patch the entity's Lookup fields by generating sub-entities.
                //
                StringBuilder code = new StringBuilder();
                code.Append(entity.Code);
                foreach (string patch in entity.Lookups.Keys)
                {
                    string lookupList = entity.Lookups[patch];
                    string lookupEntityName;
                    if (map.ContainsKey(new Guid(lookupList)))
                    {
                        lookupEntityName = map[new Guid(lookupList)];
                    }
                    else
                    {
                        a.List = lookupList;
                        Entity lookupEntity = gen.Generate(a);
                        lookupEntityName = lookupEntity.Name;
                        map.Add(lookupEntity.Id, lookupEntity.Name);
                        entities.Enqueue(lookupEntity);
                    }
                    code.Replace(patch, lookupEntityName);
                }
                entity.Code = code.ToString();

                //
                // Append the code to the accumulated code buffer.
                //
                allCode.Append(entity.Code);
            }

            foreach (string e in gen.Enums)
            {
                allCode.Append(e);
            }

            //
            // Write to output file.
            //
            Console.Write("Writing file {0}... ", a.File);

            using (StreamWriter sw = File.CreateText(a.File))
            {
                sw.WriteLine(allCode.ToString());
                Console.WriteLine("Done");
            }
        }