Angel \”Java\” Lopez on Blog

March 14, 2011

More Language Workbench Competition 2011 with AjGenesis

Filed under: AjGenesis, Code Generation, Lwc2011 — ajlopez @ 9:03 am

In my previous post I described my initial work for Language Workbench Competition 2011, using AjGenesis. Now, it’s time to write about some new tasks I wrote. You can read the tasks of the competition at:

http://www.languageworkbenches.net/LWCTask-1.0.pdf

First, I skipped Phase 0.3 (constraint checks such as name-uniqueness). I plan to complete it, but not now. I wrote Phase 0.4:

0.4 Show how to break down a (large) model into several parts, while still cross-referencing between the parts. For example, put the Car and Person entities into different files, while still having the Person -> Car reference work.

The code was committed to AjGenesis repository:

http://ajgenesis.codeplex.com/SourceControl/list/changesets

under examples/Lcw2011

This step was an easy one. The Project.txt is:

Project Lwc2011
	Entities
		Entity Person Source="Entities\Person.txt"	
		Entity Car Source="Entities\Car.txt"
	End Entities
End Project

 

The Source attribute is special in AjGenesis model loading: it indicates a separate file to load in order to complete the object. I added this feature in the early times of AjGenesis: I want to have model files that are manageable, that don’t hurt the eyes ;-)

This is Person.txt:

Entity Person
	Properties
		Property Name Type="Text"
		Property FirstName Type="Text"
		Property BirthDate Type="Date"
		Property OwnedCar Type="Car"
	End Properties
End Entity

I began to write Phase 1.0 first step:

1.1 Show the integration of several languages. Define a second language to define instances of the entities, including assignment of values to the properties. This should ideally really be a second language that integrates with the first one, not just "more syntax" in the same

grammar. We want to showcase language modularity and composition here.

This is the new model:

Project Lwc2011
	Description = "Lwc"
	Entities
		Entity Person Source="Entities\Person.txt"	
		Entity Car Source="Entities\Car.txt"
	End Entities
	
	Instances
		Instance p 
			Type = "Person"
			Properties
				Property Name Value = "Voelter"
				Property FirstName Value = "Markus"
				Property BirthDay Value = "14/02/1927"
				Property OwnedCar Value = "c"
			End Properties
		End Instance
		
		Instance c 
			Type = "Car"
			Properties
				Property Make Value = "VW"
				Property Model Value = "Touran"
			End Properties
		End Instance
	End Instances
End Project

But it's still work in progress. I could put the instances in another independent model file (Instances.txt) or I could put the each instance in a separate file, referenced by the above one using Source attribute. I should complete the tasks checking the existence of each property in the entity type that correspond to each instance. AjGenesis doesn't support Domain-Specific Language definition: the above example is still a free model. You can add any property to any instance, and the current implementation doesn't check the proper use of the model. So, this kind of check is pending work: I will add the checking logic in the tasks to execute.

Apparently, this task doesn't involve code generation. In the next task, I should check the values of the properties, too.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

March 8, 2011

AjGenesis and Language Workbench Competition 2011

Filed under: AjGenesis, Code Generation, Lwc2011 — ajlopez @ 5:33 pm

Last week, thanks to a @pmolinam, I met

Language Workbench Competition 2011

Molina had sent me the info last year, but I forget the challenge. It is mentioned in InfoQ:

Language Workbench Competition 2011 Submissions

You can read the task list at:

http://www.languageworkbenches.net/LWCTask-1.0.pdf

I don’t sure if AjGenesis could qualify as a Language Workbench: it’s more oriented to be a free-model code generation tool. It has no IDE integration, but it is flexible and language-independent. It doesn’t produce any DSL: instead, it has a free model that can be use in many ways, to describe the concepts you have to model, without attached domain specific language. @pmolinam asked if I could complete the tasks using AjGenesis, my open source codegeneration tool. My answer: Yes!

Then, some messages appeared at twitter:

Today, I started to write Phase 0, points 0.1-0.2. The example is at AjGenesis trunk, at:

http://ajgenesis.codeplex.com/SourceControl/list/changesets

under examples/Lcw2011

The first point 0.1 is:

0.1 Simple (structural) DSL without any fancy expression language or such. Build a simple data definition language to define entities with properties. Properties have a name and a type. It should be possible to use primitive types for properties, as well as other Entities.

entity Person { 
    string name
    string firstname
    date bithdate
    Car ownedCar
}


entity Car { 
    string make
    string model
}

I wrote a simple Project.txt (note that I’m using the textual model instead the XML one, see Models for AjGenesis and Textual model for Code Generation in AjGenesis ).

Project Lwc2011
    Entities
	Entity Person
	    Properties
		Property Name Type="Text"
		Property FirstName Type="Text"
		Property BirthDate Type="Date"
		Property OwnedCar Type="Car"
	    End Properties
	End Entity
	
	Entity Car
	    Properties
		Property Make Type="Text"
		Property Model Type="Text"
	    End Properties
	End Entity
    End Entities
End Project

The Phase 0-0.2:

0.2 Code generation to GPL such as Java, C#, C++ or XML Generate Java Beans (or some equivalent data structure in C#, Scala, etc.) with setters, getters and fields for the properties.

Using assets from my post Building An Application using AjGenesis (Part 4), I wrote the commands:

GenerateCSharp.cmd

GenerateJava.cmd

GenerateVbNet.cmd

I’m using additional model files for describing technology. This is my VbNet technology model:

<Technology>
	<Name>VbNet</Name>
</Technology>

Simple! This time, I'm using the XML model (in memory, textual and XML have the same features; it's only a serialization option).

Look at GenerateCSharp.cmd:

AjGenesis.Console Project\Project.txt Project\Technologies\CSharp.xml Tasks\Complete.ajg Tasks\Generate.ajg

It loads the Project.txt, the corresponding technology model, loads and executes the Complete.ajg task, and then loads and executes the Generate.ajg task. The Complete.task (see the mentioned post Building An Application using AjGenesis (Part 4)) it's used for complete the model: one thing it dows is to translate abstract types like “Text”, to the corresponding final language type, like “string” in C#, or “String” in Java.

The Generate.ajg takes the enriched model and generate the code for each entity, using templates. This is the template for C#:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
namespace ${Project.CSharp.Namespace} {
	public class ${Entity.Name}
	{
<#
	for each Property in Entity.Properties
#>
		public ${Property.CSharp.Type} ${Property.Name} { get; set; }
<#
	end for
#>
	}
}

The generated code for Person entity:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
namespace Lwc2011 {
	public class Person
	{
		public string Name { get; set; }
		public string FirstName { get; set; }
		public DateTime BirthDate { get; set; }
		public Car OwnedCar { get; set; }
	}
}

Next steps: complete 0.3, 0.4 tasks, and then, solve Phase 1. I could complete the assignment in two weeks. I will publish the advance in upcoming posts.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

October 9, 2010

Running AjGenesis using Mono and Ubuntu

Filed under: .NET, AjGenesis, Code Generation, Mono, Ubuntu — ajlopez @ 8:52 am

In these days, I am involved in the developing of a new version (complete rewriting) of a Java application, with a web interface. It is a team effort, and the majority of the members are Ubuntu fans: there are more proficient working in Linux boxes. The project has code generation using (make an educated guess.. ;-) AjGenesis, my open source code generation project. Then, the team want to run AjGenesis out of Windows.

AjGenesis is written in VB.NET, and compiled for .NET 2.0. I was afraid that I should make some change to run it under Ubuntu using Mono project. But I was wrong. Ubuntu has  Mono pre-installed. But AjGenesis use VB.NET runtime. Well, Mono has a VB.NET compiler. I launched the terminal in my Ubuntu ( in Virtual Box over Windows 2008), and executed:

sudo apt-get install mono-vbnc

(I guess this step is needed, but I didn’t try to run AjGenesis with only Mono installed).

Then, I downloaded the AjGenesis compiled binaries (from source trunk). And some examples, like AppExampleStep06.zip (described in Building an Application using AjGenesis (Part 6)).

You can run AjGenesis.Console.exe using

mono AjGenesis.Console.exe

But I marked it as executable:

chmod +xr- AjGenesis.Console.exe

so you can run it directly:

The Build folder was created! Nice!

After this first experiment, I got the source code of the project using subversion, and run the code generation script. The only gotchats were some tasks, written in AjBasic, that were creating directories in lower case and using them with one upper case letter. I fixed the bug, and now, the code generation is running. Team members are able to develop in Windows and Ubuntu, using Java, Tomcat, Maven, and AjGenesis.

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

October 4, 2010

Building an Application using AjGenesis (Part 6)

Filed under: AjGenesis, Code Generation, Open Source Projects — ajlopez @ 9:51 am

In the previous post in this series, I added a lot of stuff to manage the generation of .NET projects and solutions. That files are complicated. In contrast, to generate something alike for Java, I only need to generate the folder structure for package, and maybe add Ant or Maven files. But in .NET, I was to struggle with the structure of solution and project files. The code for this part can be downloaded from AppExampleStep06.zip. You need the compiled binaries AjGenesisTrunkBinaries.zip. The complete AjGenesis project, including the examples for this post series, can be downloaded from http://ajgenesis.codeplex.com.

One of the complicated part was to add all .cs and .vb files inside the project file. I wrote:

for each Entity in Project.Model.Entities
  TransformerManager.Transform("Templates/CSharp/EntityClass.tpl", "${Project.BuildDirectory}/${Project.Name}.Entities/${Entity.Name}.cs", Environment)
  PrjEntities.Includes.Add(CreateFileCs("${Entity.Name}"))
end for

The Includes list in PrjEntities object keeps the information of the files to add in the project file generation. Instead of adding the files in that way, now I add ALL .cs files in the C# project, and all .vb files in the VB.Net project. So, you can add your own custom files, and the project files still will reference them after regeneration of the solution. The key code is inside the Utilities/DotNetUtilities.ajg:

Sub AddVbFilesToProject(project)
  di = new System.IO.DirectoryInfo(project.Directory)
  prefix = ""
  AddVbFiles(project, name, di)
End Sub
Sub AddVbFiles(project, prefix, di)
  for each fi in di.GetFiles("*.vb")
    name = fi.Name.Substring(0, fi.Name.Length - 3)
    project.Includes.Add(CreateFileVb(prefix & name))
  end for
  
  sdirs = di.GetDirectories()
  
  for each sdir in sdirs
    AddVbFiles(project, prefix & sdir.Name & "\", sdir)
  end for
End Sub
Sub AddCsFilesToProject(project)
  di = new System.IO.DirectoryInfo(project.Directory)
  prefix = ""
  AddCsFiles(project, name, di)
End Sub
Sub AddCsFiles(project, prefix, di)
  for each fi in di.GetFiles("*.cs")
    name = fi.Name.Substring(0, fi.Name.Length - 3)
    project.Includes.Add(CreateFileCs(prefix & name))
  end for
  
  sdirs = di.GetDirectories()
  
  for each sdir in sdirs
    AddCsFiles(project, prefix & sdir.Name & "\", sdir)
  end for
End Sub

Another feature I added in this step: in the previous post, each time the generation was launched, it created all the files again. Now, it use a new routine, included in Utilities/TransformUtilities.ajg:

Sub TransformFile(tpl, target, tm, env)
  if System.IO.File.Exists(target) then
    target2 = target & ".tmp"
    tm.Transform(tpl, target2, env)
    content1 = System.IO.File.ReadAllText(target)
    content2 = System.IO.File.ReadAllText(target2)
    if content1 <> content2 then
      System.IO.File.Copy(target2, target, true)
    end if
    System.IO.File.Delete(target2)
  else
    tm.Transform(tpl, target, env)
  end if
End Sub

Now, instead of invoking the predefined object TransformerManager:

  TransformerManager.Transform("Templates/CSharp/EntityClass.tpl", "${Project.BuildDirectory}/${Project.Name}.Entities/${Entity.Name}.cs", Environment)

the task invoke the new routine, that compares the new file with the old one, and replace it only if they are different:

  TransformFile("Templates/CSharp/EntityClass.tpl", "${Project.BuildDirectory}/${Project.Name}.Entities/${Entity.Name}.cs", TransformerManager, Environment)

Next steps, for future posts: include identity to entities in model, generate database creation DLLs, DAOs, and some Java code.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

September 13, 2010

Building an Application Using AjGenesis (Part 5)

Filed under: AjGenesis, Code Generation, Open Source Projects — ajlopez @ 9:06 am

I just published a new step in this post series. The code can be downloaded from AppExampleStep05. The example:

At root folder, the example have the same three commands, as in the previous post.

GenerateCSharp.cmd
GenerateJava.cmd
GenerateVbNet.cmd

The model is the same. But I wrote new Tasks/GenerateCSharp.ajg, Tasks/GenerateVbNet.ajg. Now, you can generate a .NET solution and project. This is the GenerateCSharp.ajg:

IncludeCode "Utilities/Utilities.ajg"
IncludeCode "Utilities/DotNetUtilities.ajg"
' Create Build Directories
FileManager.CreateDirectory(Project.BuildDirectory)
FileManager.CreateDirectory("${Project.BuildDirectory}")
FileManager.CreateDirectory("${Project.BuildDirectory}/${Project.Name}.Entities")
FileManager.CreateDirectory("${Project.BuildDirectory}/${Project.Name}.Entities/Properties")
Project.Solution = CreateObject()
Project.Solution.Guid = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"
Project.Solution.WebGuid = "E24C65DC-7377-472B-9ABA-BC803B73C61A"
Project.Solution.Projects = CreateList()
PrjEntities = CreateObject()
PrjEntities.Name = "${Project.Name}.Entities"
PrjEntities.Directory = "${Project.BuildDirectory}/${Project.Name}.Entities"
PrjEntities.Includes = CreateList()
PrjEntities.Projects = CreateList()
PrjEntities.Libraries = CreateList()
PrjEntities.Guid = CreateGuid()
PrjEntities.COMGuid = CreateGuid()
Project.Solution.Projects.Add(PrjEntities)
for each Entity in Project.Model.Entities
  TransformerManager.Transform("Templates/CSharp/EntityClass.tpl", "${Project.BuildDirectory}/${Project.Name}.Entities/${Entity.Name}.cs", Environment)
  PrjEntities.Includes.Add(CreateFileCs("${Entity.Name}"))
end for
for each CsProject in Project.Solution.Projects
  TransformerManager.Transform("Templates/CSharp/CsProject.tpl", "${CsProject.Directory}/${CsProject.Name}.csproj", Environment)
  TransformerManager.Transform("Templates/CSharp/AssemblyInfoCs.tpl", "${CsProject.Directory}/Properties/AssemblyInfo.cs", Environment)
end for
TransformerManager.Transform("Templates/CSharp/Solution.tpl", "${Project.BuildDirectory}/${Project.Name}.sln", Environment)

Lot of new things! But the point is: now, I generate a solution file, and a project file. There are new files with utilities, and new templates. Note the creation of Project.Solution dynamic object, and PrjEntities.

The solution generated in C#:

A solution and project is generate for Vb.NET, too:

Next steps: don't generate again files that not changed since last time;' able to have manual code in projects and keep them; new projects (persistence, web interface, …)

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

July 14, 2010

Building an Application Using AjGenesis (Part 4)

Filed under: AjGenesis, Code Generation, Open Source Projects — ajlopez @ 7:28 pm

In this post, I will generate, from the same model, text files for C#, Java, and VB.NET. Previous posts:

Building An Application Using AjGenesis (Part 1)
Building An Application Using AjGenesis (Part 2)
Building an Application Using AjGenesis (Part 3)

The code of this post can be downloaded from AppExampleStep04.zip.

You need the latest AjGenesis binaries. You can get them from AjGenesisTrunkBinaries.zip. (the full source code is at AjGenesis Codeplex repository). You should add the bin directory to your path, to run the examples of this post.

The example now has more folder structure:

Projects\AjApp is the folder containing the model of the example, in Project.xml:

<Project>
	<Name>AjApp</Name>
	<Description>Building an Application using AjGenesis</Description>
	<Model>
		<Entities>
			<Entity Source="Entities/Customer.xml"/>
			<Entity Source="Entities/Supplier.xml"/>
		</Entities>
	</Model>
</Project>

I could add more folders, describing other projects, if needed.

At root folder, the example have three commands:

GenerateCSharp.cmd

GenerateJava.cmd

GenerateVbNet.cmd

The three commands have a similar content. This is the GenerateCSharp.cmd:

AjGenesis.Console Projects\AjApp\Project.xml Projects\AjApp\Technologies\CSharp.xml Tasks\Complete.ajg Tasks\Generate.ajg

Note there is two model: Project.xml is like the previous posts. The new one describe the technology to use, CSharp.xml:

<Technology>
	<Name>CSharp</Name>
</Technology>

Now, it’s only the name of the programming language. I could extend this model to define database, web servers to use, etc…. Then: Project.xml is the abstract model. Technologies\CSharp.xml, Technologies\VbNet.xml, Technologies\Java.xml are the models describing the technology to use. Each of the Generate*.cmd loads the abstract model, AND one of the tech ones.

The Complete.ajg:

' Set Build Directory
if not Project.BuildDirectory then
	Project.BuildDirectory = "Build/${Project.Name}/${Technology.Name}"
end if
FileManager.CreateDirectory(Project.BuildDirectory)
IncludeCode "Tasks/Complete${Technology.Name}.ajg"

Note the use of a trick: include the code of another file, to run, using a dynamic string. If Technology.Name == “CSharp”, the above task will execute CompleteCSharp.ajg:

' Some functions
' Name to use for variables
function CSharpVariableName(name)
	firstletter = name.Substring(0,1)
	
	return firstletter.ToLower() & name.Substring(1)
end function
' Name to use for Classes, Properties..
function CSharpName(name)
	firstletter = name.Substring(0,1)
	
	return firstletter.ToUpper() & name.Substring(1)
end function
function CSharpType(type)
	type = type.ToLower()
	
	if type="text" then
		return "string"
	end if
	
	if type="integer" then
		return "int"
	end if
	
	return type
end function
' Set namespace to use in CSharp code
if not Project.CSharp.Namespace then
	Project.CSharp.Namespace = CSharpName(Project.Name)
end if
' Complete Entities
for each Entity in Project.Model.Entities
	' Set the variable name to use for an entity
	if not Entity.CSharp.VariableName then
		Entity.CSharp.VariableName = CSharpVariableName(Entity.Name)
	end if
	
	for each Property in Entity.Properties
		' Set the CSharp to use in each property
		if not Property.CSharp.Type then
			Property.CSharp.Type = CSharpType(Property.Type)
		end if
	end for
end for

There are similar tasks for the others technologies: CompleteVbNet.ajg, CompleteJava.ajg. These tasks complete the model in memory (like assigning namespaces, packages, variable names to properties, build directory…)

The second task is Generate.ajg:

IncludeCode "Tasks/Generate${Technology.Name}.ajg"

Again, the old trick of dynamic include. This is the GenerateCSharp.ajg subtask:

for each Entity in Project.Model.Entities
	TransformerManager.Transform("Templates/CSharp/EntityClass.tpl", "${Project.BuildDirectory}/${Entity.Name}.cs", Environment)
end for

To compare, this is the CompleteJava.ajg:

' Some functions
' Name to use for variables
function JavaVariableName(name)
	firstletter = name.Substring(0,1)
	
	return firstletter.ToLower() & name.Substring(1)
end function
' Name to use for Classes, Properties..
function JavaName(name)
	firstletter = name.Substring(0,1)
	
	return firstletter.ToUpper() & name.Substring(1)
end function
function JavaType(type)
	type = type.ToLower()
	
	if type="text" then
		return "String"
	end if
	
	if type="integer" then
		return "int"
	end if
	
	return type
end function
' Set package to use in Java code
if not Project.Java.Package then
	Project.Java.Package = JavaName(Project.Name).ToLower()
end if
' Complete Entities
for each Entity in Project.Model.Entities
	' Set the variable name to use for an entity
	if not Entity.Java.VariableName then
		Entity.Java.VariableName = JavaVariableName(Entity.Name)
	end if
	
	for each Property in Entity.Properties
		if not Property.Java.VariableName then
			Property.Java.VariableName = JavaVariableName(Property.Name)
		end if
		
		' Set the Java to use in each property
		if not Property.Java.Type then
			Property.Java.Type = JavaType(Property.Type)
		end if
	end for
end for

and the GenerateJava.ajg:

for each Entity in Project.Model.Entities
	TransformerManager.Transform("Templates/Java/EntityClass.tpl", "${Project.BuildDirectory}/${Entity.Name}.java", Environment)
end for

There are templates for each technology. This is EntityClass.tpl for CSharp:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
namespace ${Project.CSharp.Namespace} {
	public class ${Entity.Name}
	{
<#
	for each Property in Entity.Properties
#>
		public ${Property.CSharp.Type} ${Property.Name} { get; set; }
<#
	end for
#>
	}
}

and this is EntityClass.tpl for Java:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
package ${Project.Java.Package};
public class ${Entity.Name}
{
<#
	for each Property in Entity.Properties
#>
		private ${Property.Java.Type} ${Property.Java.VariableName};
<#
	end for
	for each Property in Entity.Properties
#>
		public ${Property.Java.Type} get${Property.Name}()
		{
			return this.${Property.Java.VariableName};
		}
		public void set${Property.Name}(${Property.Java.Type} value)
		{
			this.${Property.Java.VariableName} = value;
		}
<#
	end for
#>
}

Running the three Generate*.cmds, create the Build folder, with Build\AjApp, Build\AjApp\CSharp, Build\AjApp\Java, Build\AjApp\VbNet subfolders.

The generated Customer.cs:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
namespace AjApp {
	public class Customer
	{
		public string Name { get; set; }
		public string Address { get; set; }
	}
}

The generated Customer.vb:

' Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
Namespace AjApp
	Public Class Customer
		Private mName as String
		Private mAddress as String
		Public Property Name as String
			Get
				return Me.mName
			End Get
			Set(value as String)
				Me.mName = value
			End Value
		End Property		
		Public Property Address as String
			Get
				return Me.mAddress
			End Get
			Set(value as String)
				Me.mAddress = value
			End Value
		End Property		
	End Class
End Namespace

The generated Customer.java:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
package ajapp;
public class Customer
{
		private String name;
		private String address;
		public String getName()
		{
			return this.name;
		}
		public void setName(String value)
		{
			this.name = value;
		}
		public String getAddress()
		{
			return this.address;
		}
		public void setAddress(String value)
		{
			this.address = value;
		}
}

Next steps: to generate a C# or VB.NET project, to load in Visual Studio, or an Eclipse project for Java.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

July 11, 2010

Building an Application Using AjGenesis (Part 3)

Filed under: AjGenesis, Code Generation, Open Source Projects — ajlopez @ 9:08 pm

This is the third part in this tutorial post series, about building an application using AjGenesis, my open source code generation project. Previous posts:

Building An Application Using AjGenesis (Part 1)
Building An Application Using AjGenesis (Part 2)

The code of this post can be downloaded from AppExampleStep03.zip.

You need the latest AjGenesis binaries. You can get them from AjGenesisTrunkBinaries.zip. (the full source code is at AjGenesis Codeplex repository). You should add the bin directory to your path, to run the examples of this post.

This time, I improve the code generation process. The model is the same, but now, the GenerateClasses.cmd:

AjGenesis.Console Project.xml CompleteModelCSharp.ajg GenerateClasses.ajg

has a new parameter: an intermediate task to execute, CompleteModelCSharp.ajg:

' Some functions
' Name to use for variables
function CSharpVariableName(name)
  firstletter = name.Substring(0,1)
  
  return firstletter.ToLower() & name.Substring(1)
end function
' Name to use for Classes, Properties..
function CSharpName(name)
  firstletter = name.Substring(0,1)
  
  return firstletter.ToUpper() & name.Substring(1)
end function
function CSharpType(type)
  type = type.ToLower()
  
  if type="text" then
    return "string"
  end if
  
  if type="integer" then
    return "int"
  end if
  
  return type
end function
' Set namespace to use in CSharp code
if not Project.CSharp.Namespace then
  Project.CSharp.Namespace = CSharpName(Project.Name)
end if
' Complete Entities
for each Entity in Project.Model.Entities
  ' Set the variable name to use for an entity
  if not Entity.CSharp.VariableName then
    Entity.CSharp.VariableName = CSharpVariableName(Entity.Name)
  end if
  
  for each Property in Entity.Properties
    ' Set the CSharp to use in each property
    if not Property.CSharp.Type then
      Property.CSharp.Type = CSharpType(Property.Type)
    end if
  end for
end for

New things: the definition of functions, the use of .NET method as .ToUpper(), and the completion of the model, like in:

if not Project.CSharp.Namespace then
  Project.CSharp.Namespace = CSharpName(Project.Name)
end if

I added some properties in the model-in-memory. If you don't define a namespace to use, one is created. Note the if Project.CSharp.Namespace is not defined and Project.CSharp is nothing, no exception is raised: undefined O.A.B is evaluated as nothing, and nothing is false in AjBasic (strategy borrowed from PHP).

Then, the above code enriches the model to use, taking decisions related to C#. In next posts, I will write similar code for other technologies. But it's worth to mention that this approach able to write a model, and then, when the technology is chosen, enrich them with tech info.

There is a fragment that add C# type to properties:

  for each Property in Entity.Properties
    ' Set the CSharp to use in each property
    if not Property.CSharp.Type then
      Property.CSharp.Type = CSharpType(Property.Type)
    end if
  end for

The second task is the same of the previous post, GenerateClasses.ajg:

for each Entity in Project.Model.Entities
  TransformerManager.Transform("EntityClass.tpl", "${Entity.Name}.cs", Environment)
end for

The template EntityClass.tpl:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
namespace ${Project.CSharp.Namespace} {
  public class ${Entity.Name}
  {
<#
  for each Property in Entity.Properties
#>
    public ${Property.CSharp.Type} ${Property.Name} { get; set; }
<#
  end for
#>
  }
}

now uses the new properties in model.

This is the Customer.cs generate file:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
namespace AjApp {
public class Customer
  {
    public string Name { get; set; }
    public string Address { get; set; }
  }
}

Next steps: write more tasks and templates to generate Java, VB.NET files.

As usual, I should mention this is a tutorial series. In the real life, I prefer to adopt another approach, described in my previous post AjGenetizing An Application.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

July 9, 2010

Building an Application using AjGenesis (Part 2)

Filed under: AjGenesis, Code Generation, Open Source Projects — ajlopez @ 10:06 pm

This is the second post in the serie, explaining how to build an application using AjGenesis, my open source code generation project. The previous post in this serie:

Building An Application Using AjGenesis (Part 1)

In this second part, I will generate two simple files, from the model defined in the last post.

The files for this second steps can be downloaded from AppExampleStep02.zip.

You need to download the AjGenesis binaries (trunk version) from AjGenesisTrunkBinaries.zip, expand them, AND add the bin folder to your path.

There is the command PrintEntities.cmd:

AjGenesis.Console Project.xml PrintEntities.ajg

AjGenesis.Console is the console program that launch the AjGenesis process. It receives many arguments. If the argument is an .xml file, its content is loaded in memory as an AjGenesis model (explained below). If the argument is an .ajg, the content of the file is a task, a list of commands to execute in AjGenesis. The commands are written in an interpreted language, named AjBasic.

This is the content of Project.xml (read previous post for more details):

<Project>
  <Name>AjApp</Name>
  <Description>Building an Application using AjGenesis</Description>
  <Model>
    <Entities>
      <Entity Source="Customer.xml"/>
      <Entity Source="Supplier.xml"/>
    </Entities>
  </Model>
</Project>

Once the model is loaded in memory, there is a public variable Project with dynamic properties loaded for each attribute and element. From AjBasic, we can access Project, Project.Model, and Project.Model.Entities.

The content of PrintEntities.ajg:

for each Entity in Project.Model.Entities
  Message "Entity " & Entity.Name
  
  for each Property in Entity.Properties
    Message "   Property ${Property.Name}"
  end for
end for

Note the use of for each, an AjBasic command. Message is a command to print something in the output console. The above code shows one of the features of AjBasic: string expansion. That is, the string:

“ Property ${Property.Name}”

is expanded in runtime to the content of the expression between ${ and }. If you run

PrintEntities.cmd

the output is:

Entity Customer

   Property Name

   Property Address

Entity Supplier

   Property Name

   Property Address

Now, let generate one class file in C# for each entity in model. This is the GenerateClasses.cmd:

AjGenesis.Console Project.xml GenerateClasses.ajg

This command loads Project.xml in memory, and execute the AjGenesis task:

for each Entity in Project.Model.Entities
  TransformerManager.Transform("EntityClass.tpl", "${Entity.Name}.cs", Environment)
end for

There are few public helper objects, predefined in AjGenesis environment. One of them is TransformerManager, that takes three arguments:

- The template file name

- The name of the file to generate

- The current Environment (name/values of global variables and functions, usually pointed by Environment global variable)

This is the first template in this tutorial series, EntityClass.tpl:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
public class ${Entity.Name}
{
<#
  for each Property in Entity.Properties
#>
  public string ${Property.Name} { get; set; }
<#
  end for
#>
}

A template is a text file with the content to generate, and with fragments between <# and #> that are filled with AjBasic commands. In the above template, the for each command processes each of the properties in the current entity. As in the string expansion, expressions between ${ and } are evaluated and its results are inserted in the output of template process.

This is the output generated for Customer.cs using EntityClass.tpl template:

// Entity Class, generated with AjGenesis (http://ajgenesis.codeplex.com)
public class Customer
{
  public string Name { get; set; }
  public string Address { get; set; }
}

There are still some simplifications: no namespace, all properties are strings, no id for entities, etc… I will address these issues, step by step, in future posts. Next steps: generate, from the same model, C#, VB.NET or Java class files.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

July 7, 2010

Building an Application using AjGenesis (Part 1)

Filed under: AjGenesis, Code Generation, Open Source Projects — ajlopez @ 8:45 pm

This is the first step in a tutorial about how to use AjGenesis to generate an application. The target solution will be .NET, with C#, but I will add some VB.NET, PHP and Java examples, as a “proof of concept” of the power of an abstract model.

This is the first step: write a simple model. You can write the model in XML files, or in plain text files. In this first step, I will write the model in XML format.

The initial model is a free one: you can design the model as you want. In this serie of post, I will refine the model, step by step, to show how to design a complete solution, that can be reused and extended with manual code and extensions. I want to model an enterprise application: customers, suppliers, invoices, payments, etc. Let start with Customer and Supplier.

(You can download the code from AppExampleStep01.zip (only three short XML files))

This is the Customer.xml file:

<Entity>
	<Name>Customer</Name>
	
	<Properties>
		<Property>
			<Name>Name</Name>
			<Type>Text</Type>
		</Property>
		<Property>
			<Name>Address</Name>
			<Type>Text</Type>
		</Property>
	</Properties>
</Entity>

There is a similar file for Supplier.xml. Note that there is no schema to follow: you can add any tag in a well formed document. In the next steps, I will load the model in memory, to be process by AjGenesis tasks and template. AjGenesis will recognize automatically that <Properties> is a list of tags <Property>. See that there is simple values, like <Name>, and compound ones, like <Property>.

One of the principles that guided me in my design choices was: the model (XML, text file, etc..) should not hurt my eyes. So, instead of write all the model in only one file, I wrote another XML file that include the entities:

<Project>
	<Name>AjApp</Name>
	<Description>Building an Application using AjGenesis</Description>
	<Model>
		<Entities>
			<Entity Source="Customer.xml"/>
			<Entity Source="Supplier.xml"/>
		</Entities>
	</Model>
</Project>

 

The attribute Source is a distinguished one: AjGenesis process that tag including the content of the referenced file, as it were in the parent file. When AjGenesis load the model, it will be one in memory, altought it is serialized in many  files.

Next steps: how to use this model in AjGenesis, and generate some C# files from it.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

July 4, 2010

Generating a solution with AjGenesis using NHibernate Hbm files

Filed under: .NET, AjGenesis, Code Generation, NHibernate, Open Source Projects — ajlopez @ 9:06 pm

Some months ago, I wrote an example of code generation, using .hbm files as the initial model:

Generating Code with AjGenesis Using NHibernate Hbm Files

Since then, I improved the example. You can download from the trunk at Codeplex:

I prepared a ready-to-run package, at my Skydrive:

Examples > AjGenesis > NHibernateMappingExample02.zip

This is its folder structure:

There is two projects: AjFirstExample, and AjTest. The former has only two simple entities. The latter has entities with one-to-many relation. You can generate the code for a complete .NET solution, launching commands:

GenerateAjFirstExample.cmd
GenerateAjTest.cmd

There are “shortcuts” to

GenerateProject AjFirstExample
GenerateProject AjTest

This is the solution generated for AjTest project:

You can run it as a web site:

In this example, the model, the .hbm files, was enriched with the use of meta tags, like in Employee.hbm in AjTest:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
  assembly="AjTest.Entities"
  namespace="AjTest.Entities"
  >
  <class name="Employee" table="employees">
    <meta attribute="SetName">Employees</meta>
    <meta attribute="Descriptor">Employee</meta>
    <meta attribute="SetDescriptor">Employees</meta>
    
    <id name="Id" column="Id" type="Int32">
      <meta attribute="Description">Id</meta>
      <generator class="native"/>
    </id>
    <property name="EmployeeCode" type="String">
      <meta attribute="Description">Employee Code</meta>
    </property>
    <property name="LastName" type="String">
      <meta attribute="Description">Last Name</meta>
    </property>
    <property name="FirstName" type="String">
      <meta attribute="Description">First Name</meta>
    </property>
    <many-to-one name="Department" column="IdDepartment"
                 class="AjTest.Entities.Department, AjTest.Entities" />
    <bag name="Tasks" lazy="true" inverse="true" cascade="all">
      <key column="IdEmployee"/>
      <one-to-many class="AjTest.Entities.Task, AjTest.Entities"/>
    </bag>  
    <bag name="EmployeeSkills" lazy="true" inverse="true" cascade="all">
      <key column="IdEmployee"/>
      <one-to-many class="AjTest.Entities.EmployeeSkill, AjTest.Entities"/>
    </bag>  
  </class>
</hibernate-mapping>

Note the use of the meta tag at class level, and at property level. AjGenesis run tasks, one is Tasks\LoadMappings.ajg:

include "Utilities/Utilities.tpl"
include "Utilities/FileUtilities.tpl"
include "Utilities/TypeUtilities.tpl"
Include("Utilities/NHibernateUtilities.tpl")
include "Templates/CSharp/UtilitiesCs.tpl"
include "Templates/CSharp/CSharpFunctions.tpl"
AssemblyManager.LoadFrom("Libraries/NHibernate.dll")
parser = new NHibernate.Cfg.MappingSchema.MappingDocumentParser()
if not Project.BuildDir then
  Project.BuildDir = "Build/${Project.Name}/CSharp"
end if
Project.Entities = CreateList()
for each MappingName in Project.Mappings
  filename = "Projects/${Project.Name}/Mappings/${MappingName}.hbm.xml"
  mapping = parser.Parse(OpenAsStream(filename))
    
  for each hbmclass in mapping.Items where IsType(hbmclass, "HbmClass")
    Entity = CreateObject()
    
    Project.Entities.Add(Entity)
  
    Entity.ClassName = hbmclass.name
    Entity.Name = hbmclass.name
    Entity.Namespace = mapping.namespace
    
    Message "Processing Mapping of Entity " & Entity.Name
        
    Entity.Properties = CreateList()
    
    if hbmclass.Id then
      Property = CreateObject()
      Property.Name = hbmclass.Id.name
      Property.Type = HbmTypeToCSharp(hbmclass.Id.type1, Entity.Namespace)
      Property.IsId = True
      for each meta in hbmclass.Id.meta
        Property.SetValue(meta.attribute, meta.GetText())
      end for
      Entity.Properties.Add(Property)
    end if
    
    for each meta in hbmclass.meta
      Entity.SetValue(meta.attribute, meta.GetText())
    end for
        
    for each item in hbmclass.Items
      Message "Processing Item " & item.GetType().Name
      
      if IsType(item, "HbmProperty") then
        Property = CreateObject()
        Property.Name = item.name
        Property.SetValue("Description", "Description " & item.name)
        Property.Type = HbmTypeToCSharp(item.type1, Entity.Namespace)
        Entity.Properties.Add(Property)
        for each meta in item.meta
          Property.SetValue(meta.attribute, meta.GetText())
        end for
      end if
      
      if IsType(item, "HbmManyToOne") then
        Property = CreateObject()
        Property.Name = item.name
        Property.Type = HbmTypeToCSharp(item.class, Entity.Namespace)
        Property.Reference = HbmTypeToCSharp(item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
      if IsType(item, "HbmSet") then
        Property = CreateObject()
        Property.Name = item.name
        Property.IsSet = true
        Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
      if IsType(item, "HbmBag") then
        Property = CreateObject()
        Property.Name = item.name
        Property.IsList = true
        Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
    end for    
  end for
end for

Note the use of Property.SetValue(…), Entity.SetValue(…) to enrich the in-memory model representation with the new metadata contained in mapping files. As in other AjGenesis examples, the metadata is used to show legends in presentation files, or for whatever you want to put in the tasks and templates.

This is a “proof-of-concept” example. It should be improved to use all the power of NHibernate. But it’s a demostration of the power of an initial model, to create lot of text artifacts, in this case, a ready-to-run application.

More examples are coming, this time using a free model. Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

« Newer PostsOlder Posts »

The Shocking Blue Green Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 56 other followers