Archive for the '.NET' Category

AjTalk: a Smalltalk-like interpreter

Weeks ago, I was working on my open source project AjTalk, an Smalltalk-like interpreter, written in .NET (using C#), and now, I want to present the status of that work. For years, I was interested in Smalltalk development, altought only in my free time, never as a professional developer. It’s not the first time I wrote such kind of interpreter (my first one was written in the eighties, and it was very simple: no garbage collector, only text commands), but this time I feel it could become a very complete implementation.

Current version is minimal, but it is taken form. The idea is to have dynamic objects, like in Smalltalk, and, at some point, add prototypes a la Self. The objects and the interpreter would access full .NET framework and other libraries, as I did in my AjBasic interpreter (included as part of AjGenesis code generation project).

The very initial version is now published at Google Code:

http://code.google.com/p/ajtalk/

The solution

I’m using Professional VS 2005. There are four projects in the solution.

AjTalk is the main project, a class library containing the core of the system.

AjTalk.Test01 and AjTalk.Test02 are console applications, only for manual tests.

AjTalk.Tests contains the unit tests, written using NUnit framework 2.2.8.

Most of the core system consists of interfaces, defining the base behaviors, and classes, implementing such interfaces.

The object

The base is to have an interface to represent any object:

using System; namespace AjTalk { public interface IObject { IClass Class { get; } object this[int n] { get; set;} object SendMessage(string msgname, object [] args); } }

I could make a message an object (of type Message), but for now, the message is only a name, and an array of arguments.

The index this[int n] access the intance variables. Each value in AjTalk can point to any .NET object, not only the ones that implements IObject. In this way, I can manage int, long, String, DataSet, from other IObject objects.

The class

I’m implementing a simple IClass interface, without distinguing between class, behaviours, and other classes, as in the classic Smalltalk. I’ll separate these classes in a future version. For now, I’m managing only a interface:

using System; using System.Collections; using System.Collections.Generic; namespace AjTalk { public interface IClass : IObject { IClass SuperClass { get; } string Name { get; } void DefineClassMethod(IMethod method); void DefineInstanceMethod(IMethod method); void DefineClassVariable(string varname); void DefineInstanceVariable(string varname); IObject NewObject(); IMethod GetClassMethod(string mthname); IMethod GetInstanceMethod(string mthname); int GetClassVariableOffset(string varname); int GetInstanceVariableOffset(string varname); } }

There is a dictionary of class and instance methods, and lists of class and instance variable names. It doesn’t have support for indexed variables, yet. IClass interface is now implemented in a BaseClass class.

The method

There is an interface implemented in Method class:

using System; namespace AjTalk { public interface IMethod { string Name { get; } IClass Class { get; } object Execute(IObject receiver, object [] args); } }

The concrete Method class, has an Execute method:

public object Execute(IObject receiver, object[] args) { return (new ExecutionBlock(receiver,receiver,this,args)).Execute(); }

Execution blocks have local variables and arguments. The Execute of an execution block takes the instructions (bytecodes) from “compiled” methods, and then it executes them. Here, I took a departure from Smalltalk ideas: the execution block is not an AjTalk object. In this way, I could run this interpreter without implementing a lot of base classes. I have to research the advantages and problems that this decision could have in the overall design and implementation.

The bytecodes

I must think about using a tree of objects (as in Interpreter pattern) instead of bytecodes. But in this version, bytecodes are used. These are the basic instruction that my “virtual machine” understands and executes step by step.

There is a bytecode list (an enumeration)

namespace AjTalk { public enum ByteCode : byte { Nop = 0, GetVariable = 1, SetVariable = 2, GetArgument = 3, SetArgument = 4, GetConstant = 5, GetLocal = 6, SetLocal = 7, GetClassVariable = 8, SetClassVariable = 9, GetSelf = 20, GetClass = 21, GetSuperClass = 22, NewObject = 23, Pop = 24, ReturnSub = 25, ReturnPop = 26, Add = 40, Substract = 41, Multiply = 42, Divide = 43, Send = 50 } }

The bytecodes contained in a method, are interpreted and executed by the execution block. An excerpt of that code:

 

while (ip < method.ByteCodes.Length) { ByteCode bc = (ByteCode) method.ByteCodes[ip]; Byte arg; switch (bc) { case ByteCode.ReturnSub: return null; case ByteCode.ReturnPop: return Top; case ByteCode.GetConstant: ip++; arg = method.ByteCodes[ip]; Push(method.GetConstant(arg)); break; case ByteCode.GetArgument: ip++; arg = method.ByteCodes[ip]; Push(arguments[arg]); break; ....

Test everywhere

The initial code was written in VB.NET. Last year I began to rewrote the original source code to C#. Then, this year I switched to “TDD mind”, so, late but sure, I added NUnit tests:

Bootstraping

I plan to use a text file, with an ad-hoc format, to inject the definitions of the initial classes and objects. Now, in the AjTest.Test02, there is an example of such format in Definitions.txt file:

class Point
variables x y

method
x ^x.

method
y ^y.

class Rectangle
variables point1 point2
class Square Rectangle

Next steps

There is a lot of work to do:

- Complete the hierarchy of base classes (Behaviour, Class, ….)

- More byte codes

- Support of local variables in methods

- Standard file text format

- Access to native .NET objects

- Use from .NET applications

- Define the classes and methods for a minimal implementation

- Serialization/deserialization of memory image

- Support for adding variables to a class with created instances (this is a tough problem)

- Support for become:

- And much more….

But I’m confident on the shape the project is taken. I’m applying “baby steps”, to improve the base code and functionality.

Angel “Java” Lopez
http://www.ajlopez.com/en

Distributed Agents and Fractals using DSS/VPL

Last week I wrote the base of an application running distributed agents over DSS/VPL, interchanging arbitrary messages, with automatic load balancing. You can read the details at:

Distributed Agents using DSS/VPL

Today, I extended the example with a new project, Fractal:

You can download from my Skydrive.

It has two DSS Service Components, one is the Calculator: it calculates a sector of the Mandelbrot fractal. The other component is the Renderer, that has a form to control and show the results of the calculation. The message that has the info of the sector to calculate is:

public class SectorInfo : MessagePayload { public double RealMinimum { get; set; } public double ImgMinimum { get; set; } public double Delta { get; set; } public int FromX { get; set; } public int FromY { get; set; } public int Width { get; set; } public int Height { get; set; } public int MaxIterations { get; set; } public int MaxValue { get; set; } }

Another class is the message that returns the calculation:

public class Sector : MessagePayload { public int FromX { get; set; } public int FromY { get; set; } public int Width { get; set; } public int Height { get; set; } public int[] Values { get; set; } }

The calculator splits the sector to calculate, if it too big. It can calculate all in only one step, but it is interesting to split the sector to generate more messages:

 

private void Calculate(AgentMessage msg) { LogInfo("Entering Calculator with Action: " + msg.Action); SectorInfo sectorInfo = (SectorInfo) msg.Payload; LogInfo(String.Format("X {0} Y {1} Width {2} Height {3}", sectorInfo.FromX, sectorInfo.FromY, sectorInfo.Width, sectorInfo.Height)); if (sectorInfo.Width > 100 && sectorInfo.Height > 100) SplitSector(sectorInfo); else CalculateSector(sectorInfo); }

As in the previous example, you can run this from a VPL diagram, FractalVpl1:

There is only one renderer, and two calculators agents. If you launch this VPL program, a window appears. This is the initial window content (after pressing the Calculate button):

You can drag and move the mouse to select a new region, or use the buttons to zoom in and out. Reset backs to the initial position. You can resize the window and invoke Calculate again. New colors button changes the color palette in use.

There is another VPL program, FractalVpl2, that it can be used to run the same example in a distributed way. It has a diagram with two AgentHosts:

and two nodes:

You must compile the VPL example and run as distributed nodes, using the rundeployer.cmd (see my previous post for details).

These some of the drawings the system produces:

 

Enjoy!

Angel “Java” Lopez
http://www.ajlopez.com/en

The new Microsoft baby: Live Mesh

These week, the Redmond giant announced its new creation, Live Mesh (a tech preview):

https://www.mesh.com/Welcome/Welcome.aspx

Thanks to Arvindra Sehmi post:

 http://blogs.msdn.com/asehmi/archive/2008/04/24/introducing-live-mesh.aspx

we now have a list of comments about this new Microsoft baby. Thise new redmonian inception is not easy to describe briefly, but it deserves to take a shot. It is an incursion from Microsoft into Web 2.0 and its own creation, Software plus Service world.

(for bloggers, note the use of links with screenshots, great idea Arvindra!)

This video explains the high level architecture (thanks to Matias Woloski for this link)

http://channel9.msdn.com/Showpost.aspx?postid=399577

In that list of articles, I found a good introduction by the ineffable Mary Jo Foley

Ten things to know about Microsoft’s Live Mesh

Read the point one:

1. The definition. As has become the norm with so many of its Software + Services products and strategies, Microsoft isn’t the best at coming up with a succinct Live Mesh definition. The closest I found (in a Live Mesh reviewer’s guide) was this: “Live Mesh is a ’software-plus-services’ platform and experience from Microsoft that enables PCs and other devices to ‘come alive’ by making them aware of each other through the Internet, enabling individuals and organizations to manage, access, and share their files and applications seamlessly on the Web and across their world of devices.” If I were in charge of defining Live Mesh, I think I’d go with “a Software + Services platform for synchronization and collaboration.”

Here, I detect the reborn of some ideas envisioned by Bill Joy for Jini, a technology that was born too early:

The Jini Technology Vision

Jini technology redefines the concept of a client. Instead of a fixed set of “local” devices, Jini technology supplies the Java client with a federation of remote “plug and play” devices in a dynamic configuration (the Jini Federation) that is personalized for each client. With Jini technology, the network truly becomes the client computer!

All this new move from MS could be the visible result of some of Ray Ozzie’s ideas, expressed years ago in his noteworthy memo:

The Internet Services Disruption

I guess Microsoft is moving more and more to the Internet (remember its Yahoo affaire). That’s a company that embraced the Andy Grove’s motto: only the paranoid survive. There are betting on RIA, Silverlight, web 2.0, rich client… Any number on roulette is covered, even the double zero… ;-)

One note: it’s amusing that, after all this effort, Microsoft still reveals its new tools only to US residents. Google, instead, pushed its innovations as beta or whatever, but for all the world at once. Hey, toc, toc, McFly…. some MS VP reading here? ;-)

Angel “EverMeshed” Lopez
http://www.ajlopez.com/en

AjGenesis: Generating the model from assemblies

 Darío Quintana have rewrote his program that generates an  AjGenesis model starting from compiled .NET assemblies. The last version is described at (Spanish post):

Generando con AjGenesis desde los assemblies

The image shows the main project directory content. There are other projects, with NUnit tests, examples, and compiled code.

It is interesting to see how a model (there is no fixed model in AjGenesis) could be obtained from different sources. In a previous post I described a short example, showing how to obtain a model from the database structure:

AjGenesis: Generating the model from the database

Darío, in his post, shows how he uses his project from an AjGenesis tasks:

function GetEntities(path) AssemblyManager.LoadFrom(AjGenesisFromAssemblyPath) obj = new AjGenesis.FromAssembly.Collector() list = obj.GetEntities(path,null) return list end function

This code uses the new AssemblyManager to load the library AjGenesis.FromAssembly.

The classes Model, Entity, Property are the model, like in other AjGenesis examples. The class Collector creates a Generator object. This object is in charge of the hard work, finding the entities inside an assembly:

using System.Collections; namespace AjGenesis.FromAssembly { public class Collector { public ArrayList GetEntities(string assemblyPath, string ns) { Generator g = new Generator(); g.Path = assemblyPath; g.AssemblyToObjects(); ArrayList array = new ArrayList(); foreach (Entity entity in g.Model.Entities) { array.Add(entity); } return array; } } }

Un fragmento de Generator:

 

public void AssemblyToObjects() { Assembly assembly = Assembly.LoadFrom(Path); Type[] types; types = assembly.GetTypes(); //Get all types from the assembly for (int i = 0; i < types.Length; i++) { //Veo que interfaces está implementando bool ImplementaIEntity = false; Type[] interfacesTypes = types[i].GetInterfaces(); ImplementaIEntity = true; if (ImplementaIEntity) { Entity entity = new Entity(); entity.Name = GetTypeName(types[i].Name); entity.FullName = types[i].FullName; if (types[i].BaseType != null) { entity.Inherits = GetTypeName(types[i].BaseType.Name); entity.InheritsFullName = types[i].BaseType.FullName; } PropertyInfo[] propertyInfo = types[i].GetProperties(); foreach (PropertyInfo pi in propertyInfo) { Property prop = new Property(); prop.Name = pi.Name; prop.TypeName = pi.PropertyType.Name; if (pi.PropertyType.FullName != null) { prop.TypeFullName = pi.PropertyType.FullName; } else prop.TypeFullName = string.Empty; entity.Properties.Add(prop); } _model.Entities.Add(entity); } } }

This is only a fragment of the code, see the complete project to have more detail. It uses reflection to obtain the types in an assembly, and its properties. I guess Darío wants to improve the way of detecting when a type is an entity, using interfaces and attributes.

Angel “Java” Lopez
http://www.ajlopez.com/

AjGenesis: Generating the model from the database

My code generation project AjGenesis uses one or many user-defined models to generate text artifacts, using programmable tasks and templates. When I started the project, I read the Kathleen Dollard’s book Code Generation in Microsoft .NET

One of her recommendations is take metatadata from some resource, like a database. In my opinion, not all needed metadata resides in a database schema, so, from the very beginning of the project, I follow the way of a free user-defined model (I quickly go away from the Dollard’s ideas of using XSLT transformations: I think XSLT is the devil’s work… don’t try it at your home..;-). There are many interesting points her ideas, I should write a post about her book.

But metadata from database is not discarded. It can be used, applying some work. Remember: code generation is a pragmatic solution, don’t ignore useful metadata source.

So, some months ago, I wrote a simple example inside the ones that come with AjGenesis. You can try the example, downloading the last published version of the project:

AjGenesis Versión 0.5

The example is located at examples\LoadDB directory.

It works using the Northwind database that comes as example for MS SQL Server. In the directory example, from the command line, execute

make

This command executes an AjGenesis task:

..\..\bin\AjGenesis.Console Tasks\DbProcess.ajg
pause

It connects with database:

PrintLine "Connection" AssemblyManager.LoadWithPartialName("System.Data") con = new System.Data.SqlClient.SqlConnection() PrintLine "ConnectionString" con.ConnectionString = "server=(local);uid=sa;database=Northwind" PrintLine "Command" cmd = new System.Data.SqlClient.SqlCommand() cmd.Connection = con cmd.CommandText = "select * from Information_Schema.Tables" con.Open()

This code uses the information inside Information_Schema.Tables. Take notice of the use of the new AssemblyManager, an utility in AjGenesis that loads assemblies.

Then, the code obtains the table names:

dr = cmd.ExecuteReader() TableNames = new System.Collections.ArrayList() while dr.Read() PrintLine "Table " & dr.Item("Table_Name") & ": " & dr.Item("Table_Type") TableName = dr.Item("Table_Name") if dr.Item("Table_Type")="BASE TABLE" then TableNames.Add(TableName) end if end while dr.Close()

Once this info was obtained, it gets the columns of the tables, making an in-memory model in a Tables collection:

Tables = new System.Collections.ArrayList() For each TableName in TableNames PrintLine "Loading Table " & TableName Table = new AjGenesis.Models.DynamicModel.DynamicObject() Table.Name = TableName Table.Columns = new System.Collections.ArrayList() cmd.CommandText = "SELECT * from Information_Schema.Columns where Table_name='" & TableName & "'" dr = cmd.ExecuteReader() while dr.Read() ColumnName = dr.Item("Column_Name") PrintLine "Processing Column " & ColumnName & ": " & dr.Item("Data_Type") Column = new AjGenesis.Models.DynamicModel.DynamicObject() Column.Name = ColumnName Column.DataType = dr.Item("Data_Type") if dr.Item("Character_Maximum_Length") then Column.Length = dr.Item("Character_Maximum_Length") Column.IsNumeric = false else if dr.Item("Numeric_Precision") then Column.Length = dr.Item("Numeric_Precision") Column.Scale = dr.Item("Numeric_Scale") Column.IsNumeric = true end if end if Column.SqlName = Column.Name Column.Name = Column.Name.Replace(" ","") Table.Columns.Add(Column) end while dr.Close() Table.SqlName = Table.Name Table.Name = Table.Name.Replace(" ","") Tables.Add(Table) end for

Finally, I use the old trick of visiting the model, applying a template to it to generate other model. This is an interesting idea that deserves more attention: multi-step model generation and transformation. I could inject some expert system to complete the model, and infers any missing part. The model can be a in-memory one, or it can saved in an XML file, to be adapted and improved:

FileManager.CreateDirectory("Model") for each Table in Tables TransformerManager.Transform("Templates\Table.tpl", "Model\${Table.Name}.xml", Environment) end for

A generated model as example:

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?> <Table> <Name>Region</Name> <SqlName>Region</SqlName> <Columns> <Column> <Name>RegionID</Name> <SqlName>RegionID</SqlName> <DataType>int</DataType> <Length></Length> <Scale></Scale> </Column> <Column> <Name>RegionDescription</Name> <SqlName>RegionDescription</SqlName> <DataType>nchar</DataType> <Length>50</Length> <Scale></Scale> </Column> </Columns> </Table>

Now, using AssemblyManager, we can load any .dll assembly, and use it to generate any code. Darío Quintana works with this feature to generate code from compiled code (post in Spanish Generando con AjGenesis desde los assemblies). You can download his utility from

http://code.google.com/p/darioquintana/downloads/detail?name=AjGenesis.FromAssembly.7z

One idea: we can use the Meta library from MyGenerationSoftware to obtain metadata from any supported database. Notably, now this utility has published source code.

Angel “Java” Lopez
http://www.ajlopez.com/en

Distributed Scribble with Microsoft Robotics Developer Studio and DSS

I’m playing withthe new CTP release of Microsoft Robotics Developer Studio. It has new features, as deploying and running a Visual Programming Language diagram in many nodes.

To explore some of this new functionality, I’ve write the dream of any software developer: a distributed multiuser scribble program…;-)… Well, it’s a very simple one, but it works, and it can run in many places, exposing and sharing your most inspired mouse drawings. The code can be downloaded from here.

The project

I have the 1.5 version of the MSRS and the new CTP MRDS (new acronym, guys), running in the same machine, without glitches. I’ve started creating a new Simple Dss Service RDS 2008:

The project contains one service component named DssScribble, and one Windows form, that is in charge of the drawing:

At the start of the service component, it creates the form, and connects to it using ports and its dispatcher queue:

protected override void Start() { base.Start(); // Add service specific initialization here. WinFormsServicePort.Post(new RunForm(CreateForm)); } private Form CreateForm() { return new CanvasForm(_mainPort, linePort, TaskQueue); }

Each line the user draw in the window is posted to service component, to be distributed to any interested subscriber:

[ServiceHandler(ServiceHandlerBehavior.Exclusive)] public IEnumerator<ITask> PostLineHandler(PostLine postLine) { SendNotification<PostLine>(_submgrPort, postLine); yield break; }

The lines are received in the NewLineHandler (the way to connect two components is via VPL, we’ll see later). The linePort is the port to communicate with the WinForm instance:

[ServiceHandler(ServiceHandlerBehavior.Exclusive)] public IEnumerator<ITask> NewLineHandler(NewLine newLine) { linePort.Post(newLine.Body); newLine.ResponsePort.Post(DefaultUpdateResponseType.Instance); yield break; }

The service component has no state. I use a class to transport the information of new lines to draw and distribute:

[DataContract()] public class DssScribbleState { } [DataContract()] public class DssScribbleLine { [DataMember()] public int fromX; [DataMember()] public int fromY; [DataMember()] public int toX; [DataMember()] public int toY; public DssScribbleLine() { } public DssScribbleLine(int fromX, int fromY, int toX, int toY) { this.fromX = fromX; this.fromY = fromY; this.toX = toX; this.toY = toY; } }

Drawing with VPL

The Visual Programming Language is a fascinating tool, with so many features. You can drag and drop service components from the toolbar. When the tool is launched, you can search the DssScrible service component in the left bottom toolbox:

I dropped two instances of DssScribble service component, and renamed them to DssScribble1 and DssScribble2:

I connected the instances, so they listen their notifications. Every line produced in one instance, is transmitted to the other. In this way, what you draw in a window is viewed in the other.

The connection is between the PostLine notification to a NewLine operation:

To launch the application, go to Run -> Start menu. A windows appears, showing the log messages:

Few moments, and the two instances of DssScribble service are created, each one shows a form. You can draw in any form, and the mouse drawn lines are replayed in the other form:

That is my self-portrait: my left eye with a tear, because the emotion of distributed scribbling…. ;-)

Running on distributed nodes

VPL IDE has a node designer. At the right, there is a node branch on the Project tree. Each node represents a DSS node hosting DSS service components. I added two nodes, the first containing the instance and diagram of the current application (diagrams are services that can be viewed during the debug phase in your browser, you’ll love that featuer). I dragged and dropped DssScribble2 instance to the second node:

Note the right bottom panel: I set the properties for Windows0 node, in the same localhost machine, but with other ports (Windows node will run at 50000/50001 ports). In other project, I tried to have a remote machine, and the distribution of the application worked without problems. You can define any number of nodes, each in a machine of your office, put on them DssScribble instances, related each other, and play scribbling with your coworkers (after work, please…. ;-)

In order to run the application in a distribute way, you must compile it. Use the Build -> Compile as a Service menu option. You must set a directory where to generate the code and solution. Then, VPL tool compile the solution and generate packages to deploy. You can open the generated solution with Visual Studio, if you are curious (the code is a very interesting, a very clever one, implementing, I suppose, an state or stack machine, look at Decrement and Increment methods).

Each node must have a package deployer service, running on another port (the same one for all nodes, default value is 55555). Go to run bin directory of Microsoft Robotics Developer Studio, and run the rundeployer.cmd:

 

Note: if you want to compile the service again, you must stop the deployer node: this is using the bin directory and the compilation conflicts with the package deployer host.

Now, we are ready to deploy our killer app: execute Run -> Run on distributed nodes. The system warns about to have deployers running:

And the magic begins: each node is contacted, and the application is deployer to them. A DSS node is started in each node, and its corresponding service instances are created. In this example, you will have two new old-DOS windows, running each DSS node. This is my second node window:

Now, each node show its scribbling window, and the fun begins.

Notes

I’m not using partners in this example. Instead, I’m put notification of events, in this case, new lines, so other components can receive such notification. You can write other components, other than scribble windows, to receive and process the lines. One idea is to use the coordinates of a new line to control a robot motor, or to persists the lines produced with a new persistence component. To control a robot motor, you should play with VPL, without rewriting the service component code.

Conclusions

Using VPL you can compose new applications from preexisting components. You can create your own activities, too. And using node diagrams (in VPL or using the DSS Manifest Editor) with the packager deployer, we can distribute the application in many physical nodes, in any convenient manner. But you must define each node and component: there is no provisioning of have a grid, so we can clone and distribute a working component. A gridified DSS application can be written, but in my opinion, it should be created with custom code. Idea to explore: write a custom control application that, using package deployer, deploys tasks to nodes in a grid.

All these tools opened my brain. Writing DSS service component is a new way of thinking and programming, something I want to explore for years: how to write objects with one-way message processing, in a distributed and parallel way (AjAgents was motivated by that objective). I envision some system that model Minsky ideas about the human mind.

Well, it’s a new brave world. Dorothy: we are not in Kansas anymore… ;-)

Angel “Java” Lopez
http://www.ajlopez.com/en

Code Generation as a Service with AjGenesis

I’m back! I want to write in this post about the new features I’ve added to my code generation project AjGenesis. The main points are:

- A new interactive way to use it, a web based application

- Examples with that new interface, to generate C#, VB.Net, Java and PHP applications, all from the same abstract model

These features were published last January at release 0.5 in CodePlex

Using AjGenesis

Years ago, I began to work in this project. Those days, the only way to execute and use it were the console, with commands. Later, I adopted NAnt, and NAntGui, as interfaces to launch the system and execute tasks and transformations. The project can be used as a set of .DLLs, referenced from custom application. Carlos Marcelo Santos has published posts (in Spanish) about how to use AjGenesis from NAnt

Cómo generar código con AjGenesis sirviéndonos de NAnt
Cómo generar código con AjGenesis sirviéndonos de NAnt - Parte II

Last year, 2007, Jonathan Cisneros wrote a great Windows interface, named AjGenesis Studio:

AjGenesis Studio: una IDE para AjGenesis
AjGenesis Studio at CodePlex

As an exercise at the end of year 2007, I wrote a new project in the original solution, and I published last January inside the last release 0.5 at CodePlex.

It’s a new web project, that I called, inspired by the work of Jonathan, AjGenesis Web Studio

The main point is, with this project, to show that the functionality from the AjGenesis core can be used and exposed in our applications, this time from a web interface, using ASP.NET. With this approach, we can put a server in our internal network or at Internet, and create, edit, upload and download user defined models, generate source code, and download the results. We could call this, Code Generation as a Service.

Let’s look the project, its functions and some inners.

The project

It’s a web project, named AjGenesis.WebStudio.

To launch it, load the AjGenesis.sln solution (located at src directory inside the version 0.5 from CodePlex) with Visual Studio 2005, and build the complete solution.

(If you have errors in the AjGenesis.WebStudio project, probably you must add a reference to a .DLL that manages the file compressions. Add as reference to the project the file src\Libraries\Ionic.Utils.Zip.dll. This library generates .zip files, and expand them).

In the web solution, I used Master Pages, and a default Theme. It doesn’t manage a database, only files and directories. We’ll see below that the project has a mini wiki, to write help pages that can be defined by the user.

The look and feel is simple, but you can change the theme and master page to obtain a better result.

The system can generate code in the fly, and download it as a .zip file. You can use the classic AjGenesis system, as I explained in past post, but now, we can use it from any browser. You don’t need .NET in your client machine, and you can work from other operating systems.

After the build of the solution, click right mouse button on the file \Default.aspx in project AjGenesis.WebStudio, and choose View in browser…:

This is preferred to launch the project in debug mode: if you debug the project, it will execute the code generation task in very slow way.

Working Directory

The system uses a working directory, with a structure that resembles the examples at AjGenesisExamples3.zip (to download from examples at CodePlex). The default working directory is AjGenesis.WebStudioWorkingDirectory:

Some directories:

Projects: There is a directory here for each project model.
Templates: Containing the template files to process during the code generation phase
Build: The code generated code resides in this directory.

The working directory can be changed using the left menu option Working Directory and then, choosing the option Change Working Directory:

Generating Hello World

As I used to comment in my speeches, the acid test of all code generation system is to help us to model and produce the most simple and universal software system, the reknowed Hello World example. There is an explanation on how to do this with classic AjGenesis in my post

Code Generation with AjGenesis- A Hello World application

In AjGenesis Web Studio, select the left menu option Generate. This is the result page

There are two dropdown list. We’ll see how they are filled. At the first list, there are the defined projects:

Choose HelloWorld. Then, go to technology list, showing:

In this project, only Java and Net20 are the defined technologies. Other projects have more technologies. Choose Java and the press the Generate button. After a while, the page shows a result.

How this works?

First point, the system manage a working directory, the default is AjGenesis.WebStudioWorkDirectory, a syster directory of the web project. There is a Projects project, cointaining more directory, each one is a project for the system.

The directory AjGenesis.WebStudioWorkDirectory\Projects\HelloWorld has a Project.xml file that describes the free model we use in this case:

<Project> <Name>HelloWorld</Name> <Description>HelloWorld Example</Description> <GenerateTask>GenerateHelloWorld</GenerateTask> <Message>Hello World</Message> </Project>

Inside the directory project, there is a Technologies directory. Each XML file that is found there it’s managed as a technology model in the system. Again, as I explained in my posts on AjGenesis , this file has a free model, you can put here anything to process from code generation process. The concepts of project and technology is not mandatory, but AjGenesis Web Studio takes them as special directories, and read them to obtain the list of project and associated technologies.

The technology Java.xml file contains:

<Technology> <Name>Java</Name> </Technology>

and Net20.xml contains:

<Technology> <Name>Net20</Name> </Technology>

Nothing special. The value Name inside Technology drives what steps to execute during code generation phase.

After press the generate button, the system loads the project and technology model in memory. Then, it executes the file GenerateCode.ajg located in directory Tasks. But if the project file contains a  GenerateTask tag, as in this project, that file is executed instead the default one. This is the content of Tasks\GenerateHelloWorld.ajg:

 

PrintLine "Generating HelloWorld..." if not Project.BuildDir then Project.BuildDir = "${WorkingDir}Build/${Project.Name}" end if if not Project.Title then Project.Title = Project.Name end if if not Project.Version then Project.Version = "1.0.*" end if if not Project.Language then Project.Language = "en" end if if not Project.SystemName then Project.SystemName = Project.Name end if PrintLine "Creating Directory ${Project.BuildDir}" FileManager.CreateDirectory("${Project.BuildDir}") Include "Tasks\BuildHelloWorld${Technology.Name}.ajg"

This file is written in an scripting language, a pillar of AjGenesis, affectously named AjBasic. The Project variable is the representation in memory of the tag <Project> loaded from the Project.xml file, described above. In memory, it is as an object, with properties. It’s not an static object: you can add properties in runtime, as Project.Version in the above text. If in an if sentence we asks the value of  Project.Version and this doesn’t exist, it’s not an error, the result is simply Nothing and that value is treated as false for boolean evaluations (like in other languages, notably PHP).

Finally, the last line includes an additional file to process dinamically. The string contants in AjBasic have expression expansion: all between ${ and } is evaluated. Using the value of Technology.Name (obtained from loading in memory the XML technology file), it executes BuildHelloWorldJava.ajg or BuildHelloWorldNet20.ajg. The first one contains the steps to generate a .java file:

<# PrintLine "Generating Solution ${Project.Name}" if not Project.Title then Project.Title = Project.Name end if if not Project.Version then Project.Version = "1.0.*" end if PrintLine "Creating Directories" FileManager.CreateDirectory("${Project.BuildDir}") FileManager.CreateDirectory("${Project.BuildDir}\${Technology.Name}") TransformerManager.Transform("Templates\HelloWorld\ClassJava.tpl", "${Project.BuildDir}\${Technology.Name}\HelloWorld.java", Environment) #>

This code uses inner AjGenesis utilities that create directories and expand a template file. ClassJava.tpl contains:

// // Automatically generated by AjGenesis // http://www.ajlopez.com/ajgenesis // public class HelloWorld { public static void main(String[] args) { System.out.println("${Project.Message}"); } }

All this produces the directory Build\HelloWorld\Java:

If we choose the Net20 technology, more files would be generated:

This is a more complete result. It has a VS 2005 solution file, two project directories, one in VB.NET and the other in C#, with source code and project files:

To see the generated code, its files and directories, go to left menu option Builds:

There is a directory for each project. You can download a complete directory, as a .zip file. We can create a file, download a directory, upload and expand a .zip file, and consult a help page. We can read, edit, and delete each file, in this case readme.txt.

Go to the View at HelloWorld directory:

You can browse directories, upload and download files. You can move a directory, or make a copy, to experiment without loosing the original content.

Generating C# and VB.NET solutions

After this simple example, let’s go for more. For more information about the next examples and their models, read:

Application Generation using AjGenesis

Go again to left menu Generate option. Now, we choose a project, AjSecondExample. Its technology list is more complete:

Choose CSharp2 and generate. This process creates a complete solution inside Builds\AjSecondExample\CSharp2. There is an Sql directory with DDL script to create a MS SQL Server database. Inside the Src directory, you’ll find the solution, composed of a set of projects:

This projects follows a layered archictecture, that you can modify from the templates. They use a data access layer, based on my AjFramework project, but you can change to access Enterprise Library or your own data services.

You must create the database using the generated scripts, and modify the connection string in the web.config to match your environment. The application can be compiled and executed:

The administration page shows:

Back to generate page, execute the VbNet2 technology, obtaining a directory with the same structure, now with Visual Basic.NET code:

All these depend of the specified technology inside the files at Projects\AjSecondExample\Technologies. The content of VbNet2.xml is:

<Technology> <Programming> <Dialect>VbNet2</Dialect> </Programming> <Database> <Dialect>MsSql</Dialect> <Name>AjSecondExample</Name> <Username>sa</Username> <Prefix>ajse_</Prefix> <Host>(local)</Host> </Database> </Technology>

and CSharp2.xml:

<Technology> <Programming> <Dialect>CSharp2</Dialect> </Programming> <Database> <Dialect>MsSql</Dialect> <Name>AjSecondExample</Name> <Username>sa</Username> <Prefix>ajse_</Prefix> <Host>(local)</Host> </Database> </Technology>

These data are used during the code generation process.

Note: inside Tasks\BuildTechnology.ajg file, you’ll find a new variable, injected from the web project:

if not Project.BuildDir then Project.BuildDir = "${WorkingDir}Build/${Project.Name}/${Technology.Programming.Dialect}" end if

This is the WorkingDir variable that points to the working directory we selected in AjGenesis Web Studio.

Genarating Java and JSP applications

Many projects (AjFirstExample, AjSecondExample, AjTest….) can be generated in Java with JavaServer Pages. A build.xml file is generated to be modified and used to compile the generated code using the ant utility (you can use this file from an IDE, like Eclipse or NetBeans).

The target build  makes a .war deploy file. You can browse and modify the build.xml file to install the .war in a Tomcat web container.

The generated code is composed of .jsp files (web pages in Java) and Java code to compile that implements a service layer and a data access layer, exchanging simple JavaBeans between layers. The DDL script, in these examples, is a MySql one.

If you build and deploy the application, and install the database in a MySql server, you can see it working fromn a Tomcat server:

Generating application using Domain-Driven Design ideas and Hibernate, NHibernate

Many example projects (AjFirstExample, AjSecondExample, AjTest…) have defined technologies CSharp2DDDNh, JavaDDDHb, VbNet2DDDNh, and even VbNet2Nh. The DDD ones implement some concepts from Domain-Driven Desigg, as Application, Domain and Infrastructure layer, but the templates could be improved. The *Nh projects generate code for entities using NHibernate mapping. The *Hb projects use Hibernate.

An example of NHibernate generated mapping:

 

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> <class name="AjFirstExample.Domain.Customer, AjFirstExample.Domain" table="ajfe_customers"> <id name="Id" column="Id" type="Int32" unsaved-value="0"> <generator class="native"/> </id> <property column="Name" type="String" name="Name" length="255"/> <property column="Address" type="String" name="Address" length="255"/> <property column="Notes" type="String" name="Notes" length="255"/> </class> <