Fresh Mangoes?

2014 September 16
No Comments

My previous host has had issues with their server and I felt it was time to move on. So I'm on a new host with a fresh MangoBlog install. New posts are inevitable, but the good stuff from my [old] blog will be migrated soon. Hopefully, this crash and re-incarnation hasn't been a thorn to anyone.

MSSQL money datatype and <cfqueryparam/>

2011 April 07
No Comments

This is just a quick post about the <cfqueryparam/> and cf_sql_type to use with when working with Microsoft SQL Server (MSSQL) money datatype.  While working on a recent project the client specified the db schema and I had to work with a predefined schema. I typically don't use the money datatype, when designing a db schema, preferring instead to use decimal(8,2) for fields where I'm storing monetary data.   As we began loading data into a table with money as the datatype, we noticed that amounts like 129.99 were being rounded up to 130.  The ColdFusion 9 reference for  <cfqueryparam/> does not mention the money datatype, but recommends using cf_sql_money for the double datatype.  The ColdFusion 8 reference suggests using the cf_sql_decimal type when storing data to decimal, money, smallmoney mssql datatypes.  I followed the suggestion in the CF8 reference, but ran into the rounding error.  Finally, I was hipped to the correct cf_sql_type to use by my good friend Matt Quackenbush.  He's experienced the same issue in the past and informed me that the solution is to use cf_sql_float.

An Asynchronous AOP Advice Example

2009 November 27
No Comments
Over the past year, I have dabbled more and more with leveraging AOP in my applications,primarily for logging and caching. Recently, I needed to analyze a system for performance and determined that for some operations, there were several points where third party integrations are managed. These points slowed the request lifecyle dramatically and were targeted to be re-written using cfthread. I love a good refactoring challenge as much as the next guy, but I also love a good abstraction. Thus, the AsynchronousAroundAdvice was born.

read more...

Metro 0.9 Now Available

2009 April 28
No Comments

Metro is creeping ever closer to a 1.0 release, which will likely be followed up by something else in short order.  I never really set out a timeline to development, instead, I've let the needs of my current project drive the schedule.  Today marks the 0.9 release which features one improvement (depending on how you look at it) to the TransferAuditObserver. The first cut of the Observer focused on recording create, update and delete events and the class and PK of the object which fired the event.

I needed the ability to invoke a custom method on the observer, so I re-factored the Observer to accept a tad mo' metadata. Here is the new ColdSpring configuration and a sample Observer which extends metro.model.security.TransferAuditObserver. The configuration now allows one to specify a target method by class.

<bean id="AuditMap" class="coldspring.beans.factory.config.MapFactoryBean">
    <property name="sourceMap">
    <map>
    <entry key="create">
       <map>
          <entry key="some.Class">
          <value>doSomething</value>
          </entry>
          </map>
    </entry>
    </map>
    </property>
   </bean>

   <bean id="MyObserver" class="model.package.MyObserver" lazy-init="false">
      <constructor-arg name="transfer">
         <ref bean="transfer" />
      </constructor-arg>
      <constructor-arg name="auditMap">
         <ref bean="auditMap" />
      </constructor-arg>
      <property name="SomeService">
         <ref bean="SomeService" />
      </property>
   </bean>

And here is a sample Observer.

<cfcomponent displayname="MyObserver" output="false" extends="metro.model.security.TransferAuditObserver" hint="I am a Transfer AfterCreate, AfterUpdate and BeforeDelete observer.">

   <cffunction name="doSomething" hint="Performs some important event driven action" returntype="void" output="false" access="private">
      <cfargument name="obj" type="transfer.com.TransferObject" required="true" hint="The event object">
      <cfargument name="action" type="string" required="true" hint="The action that occurred (create|update|delete).">
      
      <cfscript>
       // something gets done.
      </cfscript>
   </cffunction>

</cfcomponent>

Metro 0.8.2 Now Available

2009 March 21
No Comments

The latest release for Metro (0.8.2) is now available. This release sees the addition of another service method and some significant updates to the service api.

create
The new create returns a populated and validated Transfer object. If the object passes validation, it is persisted. The default validation context is "all". Here is the method.

<cffunction name="create" access="public" output="false" returntype="any" hint="I return a populated and validated Transfer object.">
<cfargument name="objectName" type="string" required="true" hint="The Transfer object name.">
<cfargument name="input" type="struct" required="true" hint="The input struct of key/value pairs.">
<cfargument name="context" type="string" required="false" hint="The validation context." default="all">
<cfset var obj = new(objectName: arguments.objectName)>
<cfset obj.populate(args: arguments.input)>
<cfif obj.validate(context: arguments.context)>
<cfset getGateway(arguments.objectName).save(obj)>
</cfif>
<cfreturn obj>
</cffunction>

save
The save method now also returns a populated and validated Transfer object. If the object passes validation, it is persisted. The default validation context for save() is "all". The difference between create and save is that the former populates and validates a new object, whereas the latter "gets" the object using the input struct as the key (get will intelligently build the correct key from the input struct) and uses clone(). Here is the method.

<cffunction name="save" access="public" output="false" returntype="any" hint="I return a populated and validated Transfer object.">
<cfargument name="objectName" type="string" required="true" hint="The Transfer object name.">
<cfargument name="input" type="struct" required="true" hint="The input struct of key/value pairs.">
<cfargument name="context" type="string" required="false" hint="The validation context." default="all">
<cfset var obj = get(objectName: arguments.objectName, key: arguments.input).clone()>
<cfset obj.populate(args: arguments.input)>
<cfif obj.validate(context: arguments.context)>
<cfset getGateway(arguments.objectName).save(obj)>
</cfif>
<cfreturn obj>
</cffunction>

You can probably guess that I use create when trying to persist a new object and save for an update. Let's look at a sample coldbox controller that uses create or save.

<cffunction name="doSave" access="public" returntype="void" output="false">
<cfargument name="Event" type="any">

<cfscript>
var obj = "";
var context = "";
var message = "";
if (event.getValue("UserId",0) == 0) {
// create
context = "new";
message = "User successfully Added.";
obj = getUserService().create(objectName: "User", input: event.getCollection());
} else {
// save
context = "edit";
message = "User successfully Edited.";
obj = getUserService().save(objectName: "User", input: event.getCollection());
}
if (!obj.hasErrors()) {
setMessage(type: "success", message: message);
setNextEvent("user.list");
} else {
event.setValue("User",obj);
setNextEvent(event: "user." & context, persist: "User");
}
</cfscript>
</cffunction>

In the past, the save() method returned a result with a success flag, an array of errors and the obj as a payload that you could access via getResult(). I have since moved to maintaining the errors within the Transfer object, which renders a result object useless. Thus the change to the save() method.

list
The list method now accepts the "orderBy" and "asc" arguments to provide better control of simple list operations. Here is the list() mthod.

<cffunction name="list" access="public" output="false" returntype="query" hint="I return a query by object name and filter.">
<cfargument name="objectName" type="string" required="true" hint="The Transfer object name.">
<cfargument name="filter" type="struct" required="false" default="#StructNew()#" hint="The input filter of key/vlaue pairs.">
<cfargument name="orderBy" type="string" required="false" default="" hint="The optional property name to order by.">
<cfargument name="asc" type="boolean" required="false" default="true" hint="The boolean flag to specify whether to sort ascending or descending.">
<cfreturn getGateway(arguments.objectName).list(filter:arguments.filter, orderBy:arguments.orderBy, asc:arguments.asc)>
</cffunction>

If the filter param contains properties found in the object class, the gateway will use transfer's listByPropertyMap(), instead of list().

Finally, the create(), save() and delete() methods have the Transfer transaction advice applied to them. This allows one to write more complex methods that are transaction safe.

Metro 0.7 Released

2009 March 11
No Comments

The latest Metro release (0.7) provides new behaviour to the core Service and Gateway and to the user package domain objects as well as some bug fixes, minor updates and code cleanup.  Here is a list of the important changes.

  • Added a 'reap' method to core Service and Gateway that allows one to quickly discard an instance from the Transfer Cache. If no key is specified, all instances of that class will be discarded.
  • Added several methods to the User, Role and Permission objects.

When I first started working on the code that is now Metro, I never suspected that development would proceed at the current pace. During that time, my approach to application development has changed and this has also had an impact on the Metro library. Therefore, I anticipate more change to Metro over the course of the next few releases. With my hope to have a solid API and process in place by the time Metro reaches 1.0.

I'm flattered by some of the recent interest in Metro and I admit that documentation is rather sparse. Unfortunately, I have not been in a position to fully document how to use Metro since it is somewhat in flux. I will, however, put together a brief project page to answer some of the questions I've been asked.

Enabling SSL Connections for Apache Virtual Hosts on OS X 10.5

2009 February 26
No Comments
tags: Apache · OS X

Today, I was able to get https working for localhost connections after following these step by step instructions for creating and signing a cert and updating httpd.conf and httpd-ssl.conf on Mac OS X Hints. Problem is, I need https for vhosts. When trying to connect to a local vhost over https, I encountered the following error: Error code: ssl_error_rx_record_too_long). Much more googling turned up the answer. You need to turn the SSLEngine On for vhosts. Thanks to the Ubuntu forums for that gem. Here's an example vhost that uses SSL.

<VirtualHost 127.0.0.1:443>
DocumentRoot "/Users/paul/Sites/myproject"
ServerName myproject.fancybread.local
SSLEngine On
SSLCertificateFile "/Users/paul/certs/localhost/newcert.pem"
SSLCertificateKeyFile "/Users/paul/certs/localhost/localhost.nopass.key"

DirectoryIndex index.cfm
<Directory "/Users/paul/Sites/myproject">
Options +Indexes FollowSymLinks +ExecCGI
AllowOverride AuthConfig FileInfo
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

Metro 0.6 Released

2009 February 24
No Comments

When developing OSS software, one should endeavour to maintain backward compatibility with each new release while adding improvements and new features (and fixing bugs). The current Metro release (0.6) is a significant departure from previous releases. While it maintains backward compatibility for service and gateway methods, it also provides improved support for validation rules and contexts thanks to a huge contribution from Matt Quackenbush. The changes are designed to promote building rich business objects. I removed some of the setup dependencies which I was unhappy with, and now use "import" for ColdSpring and "include" for Transfer to simplify configuration. Lastly, I have also re-organized sample code and support documents. Here is breakdown of the items requiring modification to use Metro 0.6.

read more...

Metro 0.5 Released

2009 February 07
No Comments

I'm pleased to announce the release of Metro 0.5. The biggest change for this release is compositeid support contributed by Bob Silverberg, cf.Objective() speaker and master of Transfer metadata. You'll find sample code in the new work package that models an Employee, EmployeeType and Department.

Metro 0.4.1 Released

2009 January 23
No Comments
A big thanks to John Whish for spotting a bug in the way the Metro ServiceFactory resolves component class paths. The componentPath and libPath init arguments are optional, so when both are empty strings, the ServiceFactory threw an error. This issue is resolved with revision 1 for Metro 0.4.