Click here to Skip to main content
15,894,896 members
Articles / Programming Languages / XML

Xmi CodeDom Library, Part 1

Rate me:
Please Sign up or sign in to vote.
4.23/5 (15 votes)
26 May 2008CPOL5 min read 75K   770   45  
A .Net 2.0 library that converts XMI into CodeDom. Part 1 introduces the library.
/* 
 * Copyright 2006, Dustin Metzgar
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */

using System;
using System.CodeDom;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using XmiCodeDomLib;

namespace XmiTestApp
{
    public partial class MainForm : Form
    {
    	private CodeCompileUnit _CCU = null;
    	private Mutex _CcuMutex = new Mutex();
    	    	
        public MainForm()
        {
            InitializeComponent();
            foreach (CodeOutputTypes cot in Enum.GetValues(typeof(CodeOutputTypes)))
                cboOutputType.Items.Add(cot.ToString());
            cboOutputType.SelectedIndex = 0;
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "XMI files|*.xmi|XML Files|*.xml|All files|*";
            ofd.FilterIndex = 1;
            ofd.Multiselect = false;
            if (ofd.ShowDialog(this) == DialogResult.OK)
                txtXmiFilename.Text = ofd.FileName;
        }

        private bool VerifyFile()
        {
            FileInfo fi = new FileInfo(txtXmiFilename.Text);
            if (!fi.Exists)
            {
                MessageBox.Show("File does not exist.");
                return false;
            }
            return true;
        }

        private void ShowException(Exception exc)
        {
            StringBuilder sb = new StringBuilder();
            Exception exc2 = exc;
            while (exc2 != null)
            {
                sb.Append(exc2.GetType().FullName);
                sb.Append(Environment.NewLine);
                sb.Append(exc2.Message);
                sb.Append(Environment.NewLine);
                sb.Append(exc2.StackTrace);
                sb.Append(Environment.NewLine);
                exc2 = exc2.InnerException;
            }
            MessageBox.Show(sb.ToString(), "Exception caught during processing.");
        }

        private void btnGenerate_Click(object sender, EventArgs e)
        {
            if (VerifyFile())
            {
	            CodeOutputTypes cot = (CodeOutputTypes)Enum.Parse(typeof(CodeOutputTypes), cboOutputType.SelectedItem.ToString());
                try
                {
                    XmlTextReader xtr = new XmlTextReader(txtXmiFilename.Text);
                    Thread t = new Thread(new ParameterizedThreadStart(GenerateCode));
                    t.IsBackground = true;
                    t.Start(new object[] { xtr, cot });
                }
                catch (Exception exc)
                {
                    ShowException(exc);
                }
            }
        }

        private void btnHierarchy_Click(object sender, EventArgs e)
        {
            if (VerifyFile())
            {
                try
                {
                    XmlTextReader xtr = new XmlTextReader(txtXmiFilename.Text);
                    Thread t = new Thread(new ParameterizedThreadStart(ShowClassHierarchy));
                    t.IsBackground = true;
                    t.Start(xtr);
                }
                catch (Exception exc)
                {
                    ShowException(exc);
                }
            }
        }

        delegate TreeNode AddTreeNode(TreeNodeCollection tnc, string key);
        delegate void ShowHideButton(Button btn, bool enabled);
        delegate void StartHierarchy();
        delegate void EndHierarchy();
        delegate void SetupProgressBar(int min, int max, int step);
        delegate void ProgressBarStep();
        delegate void UpdateStatusBar(string msg);
        delegate void ShowCode(string code);

        /// <summary>
        /// This delegate can be declared statically since it doesn't need access to anything in
        /// the object.  It must still be a delegate because it has to be called in the main 
        /// window's thread.
        /// </summary>
        AddTreeNode _AddTreeNode = delegate(TreeNodeCollection tnc, string key) 
        {
        	int i = 0;
        	for (; i < tnc.Count && tnc[i].Text.CompareTo(key) < 0; i++) {}
        	return tnc.Insert(i, key, key);
        };
        
        /// <summary>
        /// This delegate can be declared statically since it doesn't need access to anything in
        /// the object.  It must still be a delegate because it has to be called in the main 
        /// window's thread.
        /// </summary>
        ShowHideButton _ShowHideButton = delegate(Button btn, bool enabled) { btn.Enabled = enabled; };

        private void ShowClassHierarchy(object obj)
        {
        	// Create the delegates we need to call on the main thread.
            StartHierarchy startH = delegate() { statusBarLabel.Text = "Parsing Hierarchy..."; treeClasses.Cursor = Cursors.WaitCursor; treeClasses.Nodes.Clear(); progressBar.Visible = true; };
            EndHierarchy endH = delegate() { /*treeClasses.ExpandAll();*/ treeClasses.Cursor = Cursors.Default; statusBarLabel.Text = "Done"; progressBar.Visible = false; };
            SetupProgressBar progBarSetup = delegate(int min, int max, int step) { progressBar.Minimum = min; progressBar.Maximum = max; progressBar.Step = step; };
            ProgressBarStep progBarStep = delegate() { progressBar.PerformStep(); };
            UpdateStatusBar updStatus = delegate(string msg) { statusBarLabel.Text = msg; };

            Invoke(_ShowHideButton, new object[] { btnHierarchy, false });
            _CcuMutex.WaitOne();
            Invoke(startH);
            if (_CCU == null)
            {
            	XmlReader xr = obj as XmlReader;
            	XmiRoot root = new XmiRoot();
            	Invoke(updStatus, new object[] { "Parsing XMI..." });
            	root.Parse(xr);
            	Invoke(updStatus, new object[] { "Creating CodeDom..." });
            	_CCU = root.GetCodeCompileUnit();
            }
            CodeCompileUnit ccu = CopyCcu();
        	Invoke(updStatus, new object[] { "Parsing Hierarchy..." });
            foreach (CodeNamespace cn in ccu.Namespaces)
            {
            	TreeNode nodeNs = Invoke(_AddTreeNode, new object[] { treeClasses.Nodes, cn.Name }) as TreeNode;
                Invoke(progBarSetup, new object[] { 1, cn.Types.Count, 1 });
                for (int i = cn.Types.Count - 1; i >= 0; i--)
                {
                    CodeTypeDeclaration ctd = cn.Types[i];
                    if (ctd.BaseTypes.Count == 0)
                    {
                        Invoke(_AddTreeNode, new object[] { nodeNs.Nodes, ctd.Name });
                        cn.Types.RemoveAt(i);
                        Invoke(progBarStep);
                    }
                }
                foreach (TreeNode tn in nodeNs.Nodes)
                    GetNodeChildren(cn, tn);
            }
            Invoke(endH);
            _CcuMutex.ReleaseMutex();
            Invoke(_ShowHideButton, new object[] { btnHierarchy, true });
        }

        private void GetNodeChildren(CodeNamespace cn, TreeNode tn)
        {
            for (int i = cn.Types.Count - 1; i >= 0; i--)
            {
                if (i >= cn.Types.Count)
                    i = cn.Types.Count - 1;
                if (i < 0)
                	break;
                CodeTypeDeclaration ctd = cn.Types[i];
                CodeTypeReference ctrFound = null;
                foreach (CodeTypeReference ctr in ctd.BaseTypes)
                    if (ctr.BaseType == tn.Text)
                    {
                        ctrFound = ctr;
                        break;
                    }
                if (ctrFound != null)
                {
                    TreeNode tnChild = Invoke(_AddTreeNode, new object[] { tn.Nodes, ctd.Name }) as TreeNode;
                    ctd.BaseTypes.Remove(ctrFound);
                    if (ctd.BaseTypes.Count == 0)
                    {
                        cn.Types.RemoveAt(i);
                        ProgressBarStep progBarStep = delegate() { progressBar.PerformStep(); };
                        Invoke(progBarStep);
                    }
                    GetNodeChildren(cn, tnChild);
                }
            }
        }
        
        private void GenerateCode(object obj) 
        {
        	UpdateStatusBar updStatus = delegate(string msg) { statusBarLabel.Text = msg; };
        	ShowCode showCode = delegate(string code) { txtCode.Text = code; };
        	
        	XmlReader xr = (obj as Array).GetValue(0) as XmlReader;
        	CodeOutputTypes cot = (CodeOutputTypes)((obj as Array).GetValue(1));
            Invoke(_ShowHideButton, new object[] { btnGenerate, false });
            _CcuMutex.WaitOne();
           	XmiRoot root = new XmiRoot();
            if (_CCU == null)
            {
            	Invoke(updStatus, new object[] { "Parsing XMI..." });
            	root.Parse(xr);
            	Invoke(updStatus, new object[] { "Creating CodeDom..." });
            	_CCU = root.GetCodeCompileUnit();
            }
        	Invoke(updStatus, new object[] { "Running Code Generator..." });
        	string codeString = root.GetParsedCode(cot, _CCU);
        	Invoke(showCode, new object[] { codeString });
        	Invoke(updStatus, new object[] { "Done." });
        	_CcuMutex.ReleaseMutex();
            Invoke(_ShowHideButton, new object[] { btnGenerate, true });
        }
        
        void TxtXmiFilenameTextChanged(object sender, System.EventArgs e)
        {
        	_CcuMutex.WaitOne();
        	_CCU = null;
        	_CcuMutex.ReleaseMutex();
        }
        
        /// <summary>
        /// Makes a copy of the current CodeCompileUnit.  This is used because the methods that
        /// show the class hierarchy destroy the CodeCompileUnit.
        /// </summary>
        /// <returns></returns>
        private CodeCompileUnit CopyCcu()
        {
        	try 
        	{
        		BinaryFormatter bf = new BinaryFormatter();
        		MemoryStream ms = new MemoryStream();
        		bf.Serialize(ms, _CCU);
        		ms.Position = 0L;
        		CodeCompileUnit ccu = bf.Deserialize(ms) as CodeCompileUnit;
        		return ccu;
        	}
        	catch (Exception exc)
        	{
        		throw exc;
        	}
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Microsoft
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions