Playing with Model-Glue Unity
After watching Joe Rinehart's video on the coolness of Model-Glue: Unity, I had to download and play a bit. Pretty amazing stuff. I liked how easy it was to set up some basic functionality for a simple table. The combination of MG, ColdSpring and Reactor is quite powerful. The scaffolding (where it automatically built some event-handlers and views) part was really impressive.
The only problem I had with some of this type of automation is that I didn't feel like I had access to a separated model that I would be able to reuse elsewhere. Some of the Generic Database Modeling that MG has built into the controller would be difficult to use if I want to take MG out of the equation and reuse a part of my model. But perhaps I didn't play long enough to get a full understanding.
I briefly looked at the idea of "actionpacks" and read through the one Email Service actionpack that is available through the SVN site. This looks really cool. The Email Service is a prebuilt model that is used by simple calls to an API (e.g., setTo, setSubject()...). It comes with the necessary ColdSpring config xml, the MG Controller and the MG xml. This little actionpack would be very easy to adapt to Mach-II. It is a good example of how a part of a model can be written and reused.
Good job Joe and everyone who contributed.
Note on using Model-Glue or Mach-II with ColdSpring and Reactor
Just a reminder that in order to use Model-Glue or Mach-II with ColdSpring and Reactor you must get the latest version of all of the above. The most recent versions of MG and M-II are available at their respective web sites as they are the most recent 'stable' version. For ColdSpring and Reactor, however, you'll have to go to version control repositories. ColdSpring has the CVS login details on its website (Eclipse has a built in CVS checkout client). Reactor is harder to find. I downloaded the Tortoise SVN client (google it, download it, install it). It's repository is at svn://alagad.com/reactor/trunk (this is listed in the Reactor documentation).
There have been a lot of recent changes to the repository versions of both ColdSpring and Reactor so there is no guarantee you can get this combo to work. I do have a version of CS and Reactor that work with at least one sample application (see previous blog entry). And remember that they are both in alpha, meaning issues are being found and fixed all the time.
I'll be happy to email zips of these to whoever needs it. I'd post them here, but I don't think this free blog gives me enough file space or bandwidth. If you need them emailed, leave a comment and I can get to your email address.
Mach-II / ColdSpring / Reactor port of Brian's bookstore
Last week Brian Kotek posted a Model Glue / ColdSpring / Reactor version of his bookstore sample application. One of the comments was from Sami Hoda and how he hasn't been able to find a Mach-II / ColdSpring / Reactor sample application. I volunteered to port Brian's app to Mach II. So here is the Mach-II / ColdSpring / Reactor port of Brian's bookstore.
Converting from M-G to M-II is fairly straight forward. I didn't touch the the model cfcs, the Reactor config or the ColdSpring config. Because Brian reassigned the Model-Glue view state variables in each view template, those were easy fixes (Find 'viewstate.getvalue'; Replace with 'event.getArg'). The biggest difference is that Model Glue has onRequestStart capabilities in each of its controllers. I used Mach II plugins to mimick those.
The install should be easy enough. There is a readme file included to help you get going.
So I attended the AOP session that Chris Scott did at cf.Objective(), but I must have had a bad atte
So I attended the AOP session that Chris Scott did at cf.Objective(), but I must have had a bad attention span since I couldn't get it. Luckily though, Chris has 3 great tutorials on his blog that I was able to read through and get a better understanding from. The easiest way to get to each tutorial is look in the archives. The intro is in Sept. of 2005; Tutorial 1 is in October; and Tutorial 2 is in November.
I have a part of my app that I thought could use AOP (Aspect Oriented Programming). Basically there are numerous places that if specific data has changed, then someone wants to know about it. The currently used legacy app just has a bunch of cfifs and cfmails to handle this. Just now I set up a 'Notification Aspect' that when applied to an Update function, will see if the changing data meets the criteria for someone being notified. If so, it will log the change into a table.
The only problem I'm having is that I don't feel my Notification Aspect is abstracted very well. The tests to see if the changed data needs to be logged into a table are pretty specific. The 'before advice' I'm using now will only work for one possibility. I suppose I could do a switch statement that is based on the target and do different tests based on that. hmmm, back to Eclipse...
Service Layer part 2: thoughts on Mach II's event-bean
The event-bean term in Mach II allows you to create an object in the mach-ii.xml file. It pulls any url or form variables and will put them into a bean object if the getter and setter are defined. I was using this before doing calling the read function in my DAO, but have changed my mind.
My Mach II code looked like:
<event-handler event="getPerson">
<event-bean name="obj_PersonBean" type="myApp.model.Beans.PersonBean" />
<notify listener="PersonListener" method="getPerson" />
...other stuff and the view thing...
</event-handler>
The person listener then passed the obj_PersonBean to the PersonService.cfc using event.getArg('obj_PersonBean').
In my quest to make my the Service Layer more independent of Mach II, I decided to take out the event-bean creation in Mach II, and let the Service Layer handle it. Now my Listener just passes the Primary Key which gets into the event from the form or url. The service cfc now takes the Primary Key as an argument instead of the object. The Service layer already has the PersonBean as an object courtesy of ColdSpring Dependency Injection. The getPerson function just runs the init, passing in the Primary Key. Then the Read Function of the DAO gets the rest of the data and populates the rest of the object.
Now I need to do something similar to my update Events which still have event-bean. I guess I'll have to pass in event.getArgs() to the Service.
Note ColdSpring and Service Layers
I now have the beginnings of my legacy app rewrite working. I adapted Matt Woodward's CheckLogin filter to work as a plug in. I prefered the plugin approach for my app as you have to be logged in for every page, and didn't want to have to put a filter call into each Event Handler.
I have been setting up a Service Layer that all the Listeners call. ColdSpring handles the creation of objects and their dependencies. Very Nice. The idea of the Service Layer is to keep your domain model separate. Separate even from a framework. For example, my Person Listener does not call the Person DAO directly. Instead, it goes through a PersonService. If I ever wanted to switch frameworks, using a Service Layer makes it easier.
As a proof of concept, I wrote a simple cfm file that loads the ColdSpring bean factory and does a call to the PersonService to get some data. At first I got some errors because the ColdSpring file was relying on the MachII plugin and XML file for the dsn property. So I tried taking the DSN out of mach-ii.xml and putting it into the ColdSpring.xml. I did this using an entity.
The top of my ColdSpring.xml looks like this:
<!DOCTYPE beans SYSTEM "coldspring.dtd"
[<!ENTITY dsn "KeySym">]
>
You can declare multiple entities, just keep them between the square brackets and each one contained with its own < >. Then, in the bean definition, instead of ${dsn} which tells ColdSpring to get the dsn from Mach-II, I use &dsn; like so.
<bean id="PersonDAO" class="myApp.model.DAOs.PersonDAO">
<constructor-arg name="dsn">
<value>&dsn;</value>
</constructor-arg>
</bean>
Then I re-ran my simple cfm file that was in a totally different directory and not using Mach II at all. Bada Boom Bada Bing, I get some data back and can basically do any Service call that my Listener can do, as long as I pass the right parameters.






