Model On-The-Fly

I’m trying to setup a simple way to define simple deployments. This is in support of my most recent project, and also something that can be used by Dev Dash.

Things can be organized like this:

  • A server is one or more server types
  • Each server type may have deployed to it one or more applications
  • Each application has one or more feature
  • Each feature may have one or more web services (and other things, too, but let’s limit it to web services for now)
  • Everything needs files (assemblies, etc)
  • You can group files into lists and add the lists to other artifacts rather than duplicating files

That’s a simple hierarchy. It gets more complicated, though, because you can add things outside of the hierarchy

  • An application has features, but it can also have web services and files assigned to it directly

Dandy. To complicate it more, I want to be able to remove things. For example: Feature A contains 3 web services. But, something above it may want to remove it. IE: Start Feature 3, but exclude one of the web services.

Thus, you end up with a default configuration that you can then add to or remove from.

My first instinct was to start creating some tables to do this, but then I reconsidered and decided to use Model First in EF and let it deal with the tables. Pretty modern of me, right?

image

It’s a whole bunch of entities with many to many relationships. Ugly. Furthermore, it didn’t work. The model shows the associations between the entities. Behind the scenes, those many-to-many relationships become join tables. If I created this myself in the database, then I would add a column to join tables that would allow me to indicate REMOVE. (IE: one entity inherits a property from another entity, but in this instance I don’t want it). You can’t do that in EF other than to build the join tables as entities, which would result in a nasty model.

Another issue is that I want it to be simple The sql to maintain this (lacking a suitable gui) would be ugly too.

Thus, I began a trial-an-error effort that lasted all week. I started to write something to handle this configuration issue specifically, but quickly realized I can do so more generically.

What I came up with is an on-the-fly model. In a single text file, I identify the object and properties I want, populate the objects, and apply rules. This gives me exactly what I need in a generic way, and I will be able to use it for other things.

That said, it remains immature. One thing that I will have to do (should I pursue this) is to define the model first, then populate it after. As-is, it does whatever you want. By defining the model first, rules and relationships can be defined then enforced.

server test1
	servertypes
		add servertype App Server
		remove [servertype App Server]/applications[application testapp]/webservices[webservice service1]
 
servertype App Server
	applications
		add application testapp
		add application testapp2
 
application testapp
	features
		add feature test1
	webservices
		add webservice service1
		add webservice service3
 
application testapp2
	features
		add feature test3
		add feature test4
	webservices
		add webservice service2
 
webservice service1
	files
		add string abc.dll
		add string def.dll
		add string ghi.dll
		add string readme.txt
 
webservice service2
	files
		add string a.txt
		add string b.txt
		add string c.txt
		addlist /[filelist somefiles]/files
 
webservice service3
webservice a
webservice b
feature test1
	webservices
		add webservice a
		add webservice b
feature test3
feature test4
 
filelist somefiles
	files
		add string list1.txt
		add string list2.txt
		add string list3.txt
		add string list4.txt
 
 
 
You can resolve any of the entities that you like, but since I am primarily interested in servers, let’s see what happens when we resolve Server1.
  • It is of type app server, so it gets 2 applications, which results in 3 features and 3 web services
  • It then removes one of the webservices that it doesn’t want.

Everything is driven by ENTITY TYPE and ENTITY NAME.

Entity Type is defined as the first piece of a non-indented line.

Entity Name is defined after the space following the entity type.

The first level of indent is the property names.

The second level of indent is the commands to populate the property.

Currently, everything is treated as an entity except for string. It is coded for specifically. Other primitives will follow as needed.

All properties are assumed to be collections of entities. That too will mature as needed. IE: set the value of individual properties.

Here’s one of the entity paths:

[servertype App Server]/applications[application testapp]/webservices[webservice service1]

That is on the ServerTypes property of one of the Server entities.

  • Finds an entity in the property’s value collection of type servertype and name App Server
  • Goes into the applications property
  • Finds an entity in the property’s value collection of type application and name test app
  • Goes into the webservices property
  • Fine an entity in the property’s value collection of type webservice and name service 1

Finally, it’s where it needs to be, and it removes it.

The ADDLIST command is similar.

addlist /[filelist somefiles]/files

Because it begins with the /, it resolves [file list somefiles] rather than look for it wihtin the property collection. It finds it, drills into the files property, and copies all of the values from the files property of the list to the property that contains the command.

There is one more major thing I want to do: have things automatically collapse into each other. For example: This resolves to server/servertype/applications/features/*. I don’t really care about server type. I want to be able to specify that all of the property of server type are rolled up into server, and we never see server type in the output. But, to do that properly, I must define the model ahead of time rather than on-the-fly. (Otherwise, the collapse rules would have to be defined for each instance of the entity… that’s no good.)

This is how I consume the file:

   1: var stream = new FileStream("ParseText2.txt", FileMode.Open);

   2: var structure = new Parser().GetStructure(stream);

   3: var resolved = structure.Resolve("server", "test1");

   4:  

  • Now, if I iterate the results and dump them to the console:
  • server test1
       servertypes
          servertype App Server – ENTITY
             applications – PROPERTY
                application testapp – ENTITY
                   features – PROPERTY
                      feature test1 – ENTITY
                         webservices – PROPERTY
                            webservice a – ENTITY
                            webservice b – ENTITY
                   webservices – PROPERTY
                      webservice service3 – ENTITY
                 application testapp2 – ENTITY
                    features – PROPERTY
                       feature test3 – ENTITY
                       feature test4 – ENTITY
                    webservices – PROPERTY
                       webservice service2 – ENTITY
                          files – PROPERTY
                             a.txt – 3 strings
                             b.txt
                             c.txt
                             list1.txt – 4 strings added at once from the list
                             list2.txt
                             list3.txt
                             listr.txt

    The next step is to conver that to concrete objects. I believe I will easily achieve that via Dynamic

     

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: