# Codeuml - design UML diagrams as fast as you can code

By , 4 Jun 2012

## Introduction

Codeuml is a web based UML designer where you code the diagram using a special language and it generates the diagram on the fly. It is faster than using any visual designer where you have to drag & drop diagram elements and use mouse to connect them. Codeuml uses the open source plantuml engine to produce diagram from text. You can produce UML diagrams as fast as you can code.

This web application shows some interesting design and coding challenges. First, it shows you how to build a web based IDE like environment that mimics Windows 8 Metro UI. Second it shows how you can periodically collect data from the website, send to the server in the background asynchronously and get the result generated on the fly. Third and the most important, it shows how you can maintain a server side pool of very expensive resource that you cannot just create on every hit to the server and must have a finite pool that is shared by all your web users.

## Get the code

The live site is available at: www.codeuml.com

## Building the front-end

The UI is inspired by the metro UI in Windows 8 and it is tablet friendly. You can easily touch the buttons on a tablet. The 3 column resizable panels are built using jQuery Splitter plugin. The text editor is the awesome CodeMirror text editor that has a horrible logo. The ticker is provided by jQuery New Ticker plugin.

The 3 column view is built using the following html:

<div id="MySplitter">
<div class="SplitterPane unselectable">
<div id="umlsnippets">
.
.
.
</div>
</div>
<div id="CenterAndRight">
<div class="SplitterPane">
<textarea id="umltext" rows="10" cols="40"></textarea>
</div>
<div class="SplitterPane">
<div id="umlimage_container">
<img id="umlimage" src="img/defaultdiagram.png" />
<div id="ticker">
News ticker
</div>
</div>
</div>
</div>
</div>

First it divides the screen into 2 parts – the left side UML snippet bar and the right side that has the editor and the image. Then it divides the right side into further two parts – the text editor and the diagram image. The following javascript initializes the splitter:
// Main vertical splitter, anchored to the browser window
$("#MySplitter").splitter({ type: "v", outline: true, minLeft: 60, sizeLeft: 100, maxLeft: 250, anchorToWindow: true, resizeOnWindow: true, accessKey: "L" }); // Second vertical splitter, nested in the right pane of the main one.$("#CenterAndRight").splitter({
type: "v",
outline: true,
minRight: 200, sizeRight: ($(window).width() * 0.6), maxRight: ($(window).width() * 0.9),
accessKey: "R"
});
$(window).resize(function () {$("#MySplitter").trigger("resize");
});

Next it initializes the CodeMirror code editor over the textarea and makes it the awesome text editor.
myCodeMirror = CodeMirror.fromTextArea($('#umltext').get(0), { onChange: refreshDiagram }); myCodeMirror.focus(); myCodeMirror.setCursor({ line: myCodeMirror.lineCount() + 1, ch: 1 });  Then it initializes the left side UML snippet bar. Each button has an associated uml text which is injected to the text editor when clicked. An example of a button: <div id="scrollable"> <!-- Sequence diagram --> <h2> Sequence </h2> <div class="sequence_diagram"> <div class="button"> <div class="icon"> A&rarr;B</div> <div class="title"> Sync Msg</div> <pre class="umlsnippet">A -> B: Sync Message</pre> </div> </div>  The text that is injected to the text editor is inside the <pre> tag. You can create as many buttons as you like and just put the uml snippet that needs to be inserted in the <pre> tag with class umlsnippet. When such buttons are clicked, the following javascript injects the code inside <pre> into the text editor. $("#umlsnippets").find(".button").click(function () {
var diagramType = $(this).parent().attr("class"); if (lastUmlDiagram !== diagramType) { if (!confirm("The current diagram will be cleared? Do you want to continue?")) return; myCodeMirror.setValue(""); } changeDiagramType(diagramType); var umlsnippet =$(this).find("pre.umlsnippet").text();

var pos = myCodeMirror.getCursor(true);

// When replaceRange or replaceSelection is called
// to insert text, in IE 8, the code editor gets
// screwed up. So, it needs to be recreated after this.
myCodeMirror.replaceRange(umlsnippet, myCodeMirror.getCursor(true));

// recreate the code editor to fix screw up in IE 7/8
myCodeMirror.toTextArea();
myCodeMirror = CodeMirror.fromTextArea($('#umltext').get(0), { onChange: refreshDiagram }); myCodeMirror.focus(); myCodeMirror.setCursor(pos); refreshDiagram(); });  One tricky thing here is that if I inject text calling replaceRange, the CodeMirror editor stops working. It had to be recreated to make it work again. ## Generating diagram as you type Refreshing the diagram as you type is the most challenging part. The following javascript function gets fired as soon as something changes on the text editor. However, it makes sure it sends the UML to the server only once every second. So, even if you keep typing continuously, it will only send the UML to the server once per second. function refreshDiagram() { if (lastTimer == null) { lastTimer = window.setTimeout(function () { // Remove starting and ending spaces var umltext = myCodeMirror.getValue().replace(/(^[\s\xA0]+|[\s\xA0]+$)/g, '');

var umltextchanged =
(umltext !== lastUmlText)
&& validDiagramText(umltext);

if (umltextchanged) {
$('#ProgressIndicator').show(); lastUmlText = umltext;$.post("SendUml.ashx", { uml: umltext }, function (result) {
var key = $.trim(result);$("#umlimage").attr("src", "getimage.ashx?key=" + key);
}, "text");

try {

alert("Sorry maximum 3800 characters allowed in a diagram");
}
else {

}
}
} catch (e) {
}
}
}, 1000);
}
else {
window.clearTimeout(lastTimer);
lastTimer = null;
refreshDiagram();
}

}


There’s quite some intelligence to this code. First it ensures that it does not send the UML text to the server to go through an expensive image generation process when user is only typing space or hitting enter and there’s really no change in the text that will result in a new image to be rendered. It also does a little bit of validation to prevent half-baked diagram text from being prematurely sent to the server. The more you can catch here, the less useless image generation you can prevent on the server.

First it posts the UML text to an HTTP handler called SendUml.ashx. It remembers the text and returns a GUID. Then that GUID is used to hit the GetImage.ashx which takes care of generating the diagram. The code in SendUml.ashx is very simple:

public class SendUml : IHttpHandler {

public void ProcessRequest (HttpContext context) {
string uml = context.Request["uml"];
string key = Guid.NewGuid().ToString();

System.Web.Caching.CacheItemPriority.Default, null);

context.Response.ContentType = "text/plain";
context.Response.Write(key);
}


It just stores the text in cache for a short duration as it is expected that the browser will hit the GetImage.ashx immediately after getting the key GUID.

 public void ProcessRequest (HttpContext context) {

string key = context.Request["key"];
string umltext = context.Cache[key] as string;

context.Response.ContentType = "image/png";
context.Response.Cache.SetCacheability(HttpCacheability.Private);

if (context.Request["saveMode"] == "1")
{
}

var connection = PlantUmlConnectionPool.Get(TimeSpan.FromSeconds(15));
if (connection == null)

try
{
var uploadFileName = key + ".txt";

umltext + Environment.NewLine +
"@enduml");

using (MemoryStream memoryStream = new MemoryStream())
{
{
byte[] buffer = new byte[0x1000];
{
}

});  

First it reads the key from query string and then loads the UML text from cache. Then it gets a connection to PlantUml FTP server (explanation coming soon in next section) and uploads the UML text as a file to the FTP server. Plantuml then generates the diagram image and makes it available for download. The handler then downloads the image from the FTP server. It then adds a watermark to the image and sends back to the browser.

using (Bitmap b = Bitmap.FromStream(memoryStream, true, false) as Bitmap)
using (Bitmap newBitmap = new Bitmap(b.Width, b.Height + 20))
using (Graphics g = Graphics.FromImage(newBitmap))
{
// Put the original image on the top left corner.
g.FillRectangle(Brushes.White, 0, 0, newBitmap.Width, newBitmap.Height);
g.DrawImage(b, 0, 0);

SizeF size = g.MeasureString(WatermarkText, _font);
g.DrawString(WatermarkText, _font, Brushes.Black, newBitmap.Width - size.Width, newBitmap.Height - 15);

// Save the image to the response stream directly.
newBitmap.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png);
}

context.Response.Flush();


Once done, it returns the connection back to the pool:

PlantUmlConnectionPool.Put(connection);

That’s it from the front end side

## Generating Diagram using Plantuml

Plantuml is a Java application that can run as a FTP server where you can upload diagram text as a file and it generates a diagram image that you can download. Since it runs as a FTP server, I have to maintain a pool of running FTP servers. I cannot just start the FTP server and then generate the image. It will be too slow. So, I have to launch couple of instances of FTP servers during application startup and then maintain a pool of connections to FTP server. Whenever a hit to getimage.ashx comes in order to generate the diagram, it gets one connection from the pool, serves the request and then returns the connection to the pool. This is a common pattern you can use when you have to share a finite number of expensive resources across many demanding customers.

First I maintain a pool of running Plantuml instances. During Application_Start event, the following code launches couple of Plantuml FTP servers and prepares a pool of connections.

public static class PlantUmlProcessManager
{
private static readonly List<Process> _processes = new List<Process>();

public static void Startup()
{
if (_processes.Count > 0)
Shutdown();

var javaPath = ConfigurationManager.AppSettings["java"];

if (!File.Exists(javaPath))

var host = ConfigurationManager.AppSettings["plantuml.host"];
var startPort = Convert.ToInt32(ConfigurationManager.AppSettings["plantuml.start_port"]);
var instances = Convert.ToInt32(ConfigurationManager.AppSettings["plantuml.instances"]);

var plantumlPath = ConfigurationManager.AppSettings["plantuml.path"];
if (!File.Exists(plantumlPath))

for (int i = 0; i < instances; i++)
{
var argument = "-jar " + plantumlPath + " -ftp:" + (startPort + i);
ProcessStartInfo pInfo = new ProcessStartInfo(javaPath, argument);

pInfo.CreateNoWindow = true;
pInfo.UseShellExecute = false;
pInfo.RedirectStandardInput = true;
pInfo.RedirectStandardError = true;
pInfo.RedirectStandardOutput = true;

Process process = Process.Start(pInfo);

PlantUmlConnection connection = new PlantUmlConnection();
connection.Connect(host, startPort + i);
PlantUmlConnectionPool.Put(connection);
}
}


The connection pool is defined as following:

 public static class PlantUmlConnectionPool
{
private readonly static Queue<PlantUmlConnection> _connectionPool = new Queue<PlantUmlConnection>();
private readonly static ManualResetEvent _availableEvent = new ManualResetEvent(false);

public static PlantUmlConnection Get(TimeSpan timeout)
{
if (_connectionPool.Count == 0)
{
_availableEvent.Reset();
if (_availableEvent.WaitOne(timeout))
{
return _connectionPool.Dequeue();
}
else
{
return null;
}
}
else
{
lock (_connectionPool)
{
if (_connectionPool.Count == 0)
return null;
else
return _connectionPool.Dequeue();
}
}
} 

The algorithm is as following:

• Check if there’s a free connection available in the pool.
• If not, then wait for a fixed duration until some connection becomes available.
• If no connection is available after waiting the timeout period, then return null.

Putting connection back to the pool is very simple:

    public static void Put(PlantUmlConnection connection)
{
lock (_connectionPool)
_connectionPool.Enqueue(connection);

<span class="Apple-tab-span" style="white-space: pre; ">	</span>_availableEvent.Set();
}  

In order to maintain a connection ready to the running FTP servers, I have used Alex Pilotti’s FTP client.

public class PlantUmlConnection : IDisposable
{
private FTPSClient client = new FTPSClient();
private string _host;
private int _port;
public void Connect(string host, int port)
{
_host = host;
_port = port;
Debug.WriteLine("Connecting to FTP " + host + ":" + port);
client.Connect(host, port,
ESSLSupportMode.ClearText,
null,
null,
0,
0,
0,
3000,
true,
EDataConnectionMode.Active
);
Debug.WriteLine("Connection successful " + host + ":" + port);
}  

During the initialization of FTP servers, for each instance of FTP server, one instance of this connection class establishes an open connection.

When a diagram needs to be generated, it uploads a text file to the FTP server containing the diagram text. Then the Plantuml engine kicks in and generates the image.

public void Upload(string remoteFileName, string content)
{
Debug.WriteLine("Uploading to " + _host + ":" + _port + "/" + remoteFileName);
using (var stream = client.PutFile(remoteFileName))
{
byte[] data = Encoding.UTF8.GetBytes(content);
stream.Write(data, 0, data.Length);
}
Debug.WriteLine("Successfully uploaded " + _host + ":" + _port + "/" + remoteFileName);
}


public void Download(string remoteFileName, Action<Stream> processStream)
{
using (var stream = client.GetFile(remoteFileName))
{
processStream(stream);
}

Debug.WriteLine("Successfully downloaded " + _host + ":" + _port + "/" + remoteFileName);

}


That’s all about managing PlantUML server.

## Setting up codeuml on your own

You can install codeuml on your own server. In that case, please follow the readme file carefully. It requires some very careful setting in order to get Plantuml engine to work. I will paste the readme file for your convenience but do keep checking the latest code and read me file.

There are several pre-requisits before you run this website.

1. Install Java
===============
you are installing java. Usually it will be:
"c:\Program Files\Java\jre6\bin"

1. Configure Graphviz
=============================================================
First, you have to install graphviz.
http://www.graphviz.org/
Once you have installed, create a SYSTEM environment variable
called GRAPHVIZ_DOT which points to the dot.exe found in the
graphviz bin folder. Usually it is:
c:\Program Files\Graphviz2.26.3\bin\dot.exe
Once you have done so, start a new command line window and run
this:
set graphviz_dot
If this shows you:
GRAPHVIZ_DOT=c:\Program Files\Graphviz2.26.3\bin\dot.exe
Then it is ok.

2. Installing on IIS 7+
=============================================================
If you are hosting this on a Windows Server, there are various
steps you need to do:
* First create a new app pool.
* Create a new website or virtual directory that points to this
website.
* Give the app pool user (IIS AppPool\YourAppPoolName or NETWORK
SERVICE)
Read & Execute permission on the:
** Java folder. Eg. "c:\Program Files\Java\jre6\bin"
** Graphviz bin folder: Eg c:\Program Files\Graphviz2.26.3\bin
** Within this website:
plantuml folder.

3. Configuring web.config
==============================================================
You must fix the following entries before you can run:
These are both absolute paths. No relative path allowed.

4. Running and testing the website
============================================================
Run the Manage.aspx.

It will take a while to start the page as it tries to launch java
and run the plantuml engine at the application_start event.
Once the site is up and running, click on Test button to test
a UML generation. If it works, you have configured everything
properly.
Disable the Manage.aspx on production.

## Conclusion

Codeuml as a web application is small but it shows how to build highly responsive AJAX front-end that mimics Visual Studio like IDE and generates output form the server using some very expensive pool of finite resource. It shows you how you can implement a pool of expensive resource on your own.

 Omar Al Zabir Architect BT, UK (ex British Telecom) United Kingdom Member

Votes of 3 or less require a comment

 Search this forum Profile popups    Spacing RelaxedCompactTight   Noise Very HighHighMediumLowVery Low   Layout Open AllThread ViewNo JavascriptPreview   Per page 102550
 First Prev Next
 My vote of 5 Oshtri Deka 12 Feb '13 - 0:58
 As usual. mark merrens 3 Oct '12 - 12:53
 Have you ever written a bad article?   As always, to the point and very useful. "If you think it's expensive to hire a professional to do the job, wait until you hire an amateur." Red Adair. nils illegitimus carborundum   me, me, me Sign In·View Thread·Permalink
 very nice CIDev 18 Jul '12 - 3:53
 My vote of 5 manoj kumar choubey 15 Jul '12 - 18:16
 Alternative -easy and fast online solution NIRAL SONI 7 Jul '12 - 23:39
 Hi, Whatever you have demonstrated looks very nice. It seams that you have just tried to provide sequence diagram and not whole set of UML diagrams.   There is an online website which does provide same thing without single line of extra scripting. Just write the flow of your diagram and there you go. The site is - http://websequencediagrams.com[^]   Hope you all like it.   Regards, Niral Soni Thanks & Regards, Niral Soni Sign In·View Thread·Permalink
 Re: Alternative -easy and fast online solution Omar Al Zabir 7 Jul '12 - 23:42
 It has sequence, usecase, class and component diagrams.   Basically you can make any diagram that Plantuml supports and Plantuml supports all UML diagrams.   websequencediagrams only supports sequence diagrams.   Not sure I understand what you mean codeuml requires scripting. You can go to codeuml.com and design your diagrams without requiring any scripting. I have made codeuml.com open source and provide the full source code in case you want to install it locally. websequencediagram is closed source. (regards) => "Omar AL Zabir" + "C#, ASP.NET MVP" + "http://omaralzabir.com"; Sign In·View Thread·Permalink
 My vote of 5 conmajia 5 Jul '12 - 5:44
 My vote of 5 fredatcodeproject 18 Jun '12 - 6:00
 My vote of 5 Aamer Alduais 15 Jun '12 - 18:58
 My vote of 5 Slacker007 14 Jun '12 - 6:11
 Excellent man, truly cool Sacha Barber 14 Jun '12 - 5:56
 Nice one, easy 5 from me Sacha Barber Microsoft Visual C# MVP 2008-2012Codeproject MVP 2008-2012Open Source ProjectsCinch SL/WPF MVVM Your best friend is you. I'm my best friend too. We share the same views, and hardly ever argue   My Blog : sachabarber.net Sign In·View Thread·Permalink
 Re: Excellent man, truly cool Omar Al Zabir 21 Jun '12 - 12:53
 My vote of 5 santosh poojari 11 Jun '12 - 17:20
 My vote of 5 Marcelo Ricardo de Oliveira 6 Jun '12 - 5:12
 Excellent job, Omar. I've seen something like this made with WPF, but online is even better   cheers, marcelo There's no free lunch. Let's wait for the dinner.   Take a look at Silverlight Pronunciation Test here in The Code Project. Sign In·View Thread·Permalink
 Excellent stuff. db7uk 6 Jun '12 - 4:56
 Omar, once again a fantastic article. I have been using websequencediragrams.com for some time after reading one of your previous articles/comments (cant rememeber now which one) and love doing diagrams this way. Love the metro look! Sign In·View Thread·Permalink
 Re: Excellent stuff. Omar Al Zabir 21 Jun '12 - 12:54
 Re: Excellent stuff. db7uk 24 Jun '12 - 11:11
 Hi Omar, Sorry for the late reply. No, I have not found an issue with it however, it would (and just a really really minor thing) be really handy to be able to save not only the image but also the script that created the image. With most things in life, things change and so do diagrams Not a problem as one can copy paste from notepad but just a suggestion. Great article and app regardless. Sign In·View Thread·Permalink
 Wow, great stuff! dave.dolan 6 Jun '12 - 1:57
 I have had this sort of burning bug in my mind about finding a quicker way to do these damned UML diagrams for a long time. This is not only a neat idea, but a very useful concept! I have many bad memories of being in Visio or StarUML, clicking on 400 too many things and typing one word into a popup text box and dragging things around just-so only to have to rejigger everything when I decided to add something or propagate something. There has always been this mismatch in the purpose of UML-as-sketch and the difficulty of specifying it succinctly (even if most UML tools have 'friendly' GUIs that are so simple a caveman could do it... as long as he has the entire stone age to burn on it.) Nice work! Sign In·View Thread·Permalink
 Re: Wow, great stuff! Omar Al Zabir 21 Jun '12 - 12:54
 Thanks. Did you find any issues using it so far? (regards) => "Omar AL Zabir" + "C#, ASP.NET MVP" + "http://omaralzabir.com"; Sign In·View Thread·Permalink
 My vote of 5 S10ghen 5 Jun '12 - 22:20
 I want to say thank you and report an issue popart 4 Jun '12 - 23:24
 I like the very much, but it has problems with writing in non english language, as I understand it is problem of the PlantUML java lib or the connection between .NET and java code. Do you have an idea how to workaround this?   Anyway great work and tutorial on integration of so diferent and heterogenious technologies! Thank you Sign In·View Thread·Permalink
 Re: I want to say thank you and report an issue Omar Al Zabir 21 Jun '12 - 12:55
 My vote of 5 Vllado2 4 Jun '12 - 22:40
 My 5 Mehdi Gholam 4 Jun '12 - 19:13
 Interesting concept and implementation.   My 5! Its the man, not the machine - Chuck Yeager If at first you don't succeed... get a better publicist If the final destination is death, then we should enjoy every second of the journey. Sign In·View Thread·Permalink
 My vote of 5 Mohammad A Rahman 4 Jun '12 - 12:25