| By Simon Horwith | Article Rating: |
|
| April 13, 2005 12:00 AM EDT | Reads: |
11,736 |
Novice programmers often ask for advice about the best way to learn ColdFusion. Fortunately for them, there is a wealth of curricula, web sites, knowledge bases, books, tutorials, and other materials to help a budding young developer blossom into a decent ColdFusion developer.
What about the more seasoned developers? What resources are there to help them improve? One thing that I always suggest to experienced developers looking to improve their skills, is to try their hand at solving puzzles or at writing generic, flexible solutions to common problems.
A good way to do this is by coding generic implementations of common object-oriented design patterns. I've written several APIs and design pattern implementations for fun in the past. When I realized that other developers were interested in doing the same and in seeing how others approached this, I began writing articles about some of the generic and not so generic APIs I have written. Most recently I wrote about creating an SVG Gantt Chart API [CFDJ volume 7 issue 1], and in the October 2004 issue I wrote about creating a generic implementation of the Data Transfer Hash (DTO) J2EE design pattern [CFDJ volume 6 issue 10]. I received a lot of positive feedback from readers who want to see more articles that not only explain design patterns but also how to implement them. This month's issue being focused on architecture, I thought it only appropriate that I try my hand at implementing yet another design pattern in CFML and writing about it. This time around I decided to introduce the Resource Pool design pattern.
Resource Pools in General
The idea behind the resource pool design pattern is relatively simple. You have a central object that contains many threads that other objects can request and release. It's similar to a "factory" pattern, only in a factory pattern when an object asks the factory for a specific object, the factory creates a new object instance and returns it. A resource pool is different in that it is just that - a "pool" of resources that are already instantiated and waiting to be put to use.Like the factory pattern, you need look no further than under your nose (actually, under ColdFusion's hood) to see examples of resource pools at work. One classic example of the resource pool pattern at work is in the way the ColdFusion Application Server handles database connectivity. Have you ever noticed areas in the ColdFusion Administrator where you can define the number of available threads to perform actions such as the number of available connections to a datasource as well as thread behavior such as whether or not to maintain those database connections? Well these settings are really just parameters that define resource pools that ColdFusion uses to handle requests for certain functionality or outside resources. The example of database connection threads is the classic one and is easy to understand - CF has a certain number of connections to the database that it keeps alive and ready to accept requests to pass SQL to a datasource. This resource pool of database connections optimizes (speeds up) database connectivity in our applications because each time ColdFusion processes a CFQUERY tag it does not have to look-up the datasource information and establish a connection to the database - it simply requests a connection from the pool.
Resource Pools in a CFML App
There is still the question of what use a resource pool would be in a CFML application - and it's a good question indeed. The truth is that, by and large, ColdFusion applications don't need a resource pool implementation. The application server itself has many underlying resource pools so that you don't have to - it handles database threads, threads for asynchronous HTTP request processing, memory access, and much more. That said, a resource pool implementation in CFML is not a complete waste. I am usually the first person in a room to claim that ColdFusion Components are by far the most significant feature ever to be introduced to the CFML programming language; however, that's not to say that CFCs don't have any negative qualities. Specifically, there is a lot of overhead that comes with the actual instantiation of a CFC. In fact, if it weren't for the ability to persist CFCs in the application and session scopes, I wouldn't recommend their widespread use.In a high traffic site or an application with the demand for an unusually large number of objects in memory at any moment, reusing CFC instances that are already in memory can offer significant performance benefits. An example of this might be a high traffic eCommerce site - having a pool of available shopping cart objects in memory might drastically speed things up.
The resource pool design pattern can also be used to restrict access to resources in an application. One example would be to prevent simultaneous log-ins in a secure application. Supposing I had an application with many different user accounts that can authenticate, but I want to prevent the same username and password from being used to log in simultaneously - I want to prevent one user from creating many sessions either from several different browsers or several different physical machines at once. Another example of controlling access to objects would be in a content management system (CMS). A CMS allows people to log in as content authors; a resource pool with one object instance for each editable piece of content would ensure that no two authors could attempt to edit the same content at once. These are just a few examples - there are many other scenarios where a resource pool pattern could be used to enhance performance and/or thread access to system objects.
Implementing a Resource Pool
So how do you actually implement a resource pool in code? There are several ways to build a resource pool - most should involve a CFC that internally stores an array or structure of object instances. At the very least this CFC should have a method for requesting a new object instance from the pool. There are many other features one could add. The following describes how I implemented a generic resource pool.My resource pool application consists of two files: a resource pool CFC and a custom tag, which gives applications an easy interface to use the CFC. Any implementation of the resource pool API that I created also requires a third file - an XML file that defines all of the resource pools that you want to instantiate. The resource pool CFC has an init method that requires that you define for each pool: the (full package) name of the CFC that this pool contains instances of, the default minimum size (number of instances) for the pool, the growth rate for the pool, the maximum size the pool is allowed to grow to, and a timeout. The timeout is a number, representing the maximum number of seconds that may pass between one request for a specific instance and the next. The growth rate is a number representing how many additional object instances to create in the pool when all of the threads in the pool are currently in use. If the maximum size is 0 then growth is never restricted, otherwise the number of object instances in the pool will never exceed this number.
When the resource pool CFC is instantiated, it stores all of the parameters passed to its init method in its private variables scope and creates a private structure that is the actual pool. It then loops from 1 to the default pool size value and calls an "addResource" method. Add resource doesn't simply create an instance of an object. In order to persist, control access to, and track timeouts for instance there is some additional information required about each instance in the pool. Add resource creates a new key (with a UUID value) in the "pool structure." This new key is also a structure containing a "dts," "vacant," and "object" key. The "object" key value is a new object instance, the "vacant" key value is a Boolean representing whether or not that object is currently in use, and the "dts" key is a timestamp used to track the date of last access. Before creating a new key in the pool structure, the add resource method first calls a private method that returns a Boolean value specifying whether or not the pool will accept a new thread (i.e. has the maximum size been reached). That method also calls a "clean up" method that sets the "vacant" property to "true" for any instance that has timed out and deletes any object instance that is currently not in use until the minimum pool size is reached.
In writing the resource pool implementation I had to violate one of my own best practices. As a best practice I try never to use the "this" scope in component instances, preferring to use the private "variables" scope instead. Unfortunately, the need arose to set a property in the "this" scope of each instance in the pool. Though every instance in the pool occupies a unique key in a pool structure, that ID alone is not adequate to identify the object.
The reason for this is as follows: imagine a user requests a thread. On each request they ask the resource pool for the thread they are currently using - identifying it by the UUID name of the pool key in which it exists. A second person comes to the site and also asks for a new thread. The first user's object, which is in use, has timed out and so the resource pool gives our second visitor the first user's object. Then the first user does ask for their object (suppose they'd just gone to get a cup of coffee and the pool has short timeouts). How does the resource pool know that it has given that user's object to another user? When an object instance is returned to the pool to be reused, I cannot simply change that UUID value. The only way to do this would require deleting the key and creating a new one, which defeats the purpose of the pool - remember, you can't "duplicate()" CFC instances.
In order to get around this, I create an "rPoolID" property on each object instance - assigning it a UUID value. Clients use this UUID value to specify which object in the pool they would like. Whenever a resource is returned to the pool for reuse, the instance is kept in memory - only the UUID on its public property is reset to a new UUID. In our scenario above, when our first user asks for their object instance (which has been reallocated to another client) the resource pool will return another vacant instance from the pool. Yes, this does mean that any data that was in the old instance will be lost, but that's what happens when things time out. It's important to note that if the object that the pool contains instances of is one that holds client-specific properties, then when that object is returned to the pool (and subsequently given to another client) it will still contain the last client's data. In order to keep the resource pool generic and flexible it does not call an "init" method or any other constructor on an object instance when it's put to use. To get around this, either call the init method from the client the first time an instance is requested (or whenever the instance's public ID value changes) or modify the resource pool itself. Note that modifying the resource pool itself will most likely make it less (or not at all) generic.
The resource pool component also contains methods for getting and setting certain global pool parameters such as the default minimum thread size, a method for getting an array of structures that contains information about the current pool member statistics, and a method for manually returning an instance to the pool rather than waiting for the timeout period to expire.
The custom tag is relatively simple - it gives a simple interface for requesting an (existing or new) object from the pool, releasing an object instance back to the pool, and for reinitializing one or all resource pools. On every call, the tag expects the path to an XML file containing definitions for all of the resource pools to create as well as the fully qualified package name of the resource pool CFC. On each request if the "application" scope does not contain a key called "stRPool", the tag will create that key as a new structure, open and parse the XML file, and will create a new resource pool as the value of a key in "application.stRPool". The name of each pool is specified by a "name" attribute in each <pool> node in the XML file (a <pool> node defines one resource pool).
Summary
So that's about it - one relatively simple CFC, one very simple custom tag, and an XML file definition are all it takes to implement a flexible and generic resource pool implementation in any CFML application running on CFMX.I didn't take advantage of any new features in CFMX 7 (nor did I need to), so that people could use the resource pool on CFMX 6.1 as well as CFMX 7. In any application that uses this API, I would most likely persist the ID of a user's object instance retrieved from the pool in the session scope. In an application running on CFMX 7, you could take advantage of the new event framework and have threads automatically retrieved and returned to the pool in the "onSessionStart" and "onSessionEnd" methods in Application.cfc (see my article in last month's issue for more on the event framework).
The code for my generic resource pool application, along with a simple sample that allows you to monitor and interact with several pools at once, is available for free download from www.horwith.com/downloads/rpool.zip. I suggest looking for other design patterns to try your hand at implementing in CFML, and give it a shot! Let me know what you come up with and what the development process was like. If you think you'd like to write about it in an upcoming issue of ColdFusion Developer's Journal, don't hesitate to let me know.
On a side note, I will be speaking about API creation and code reuse at the Powered by Detroit conference in April and will be giving a six hour hands-on session on implementing design patterns and writing APIs to maximize code reuse at the CFUnited conference at the end of June. I am also currently in the process of writing a book as well as a class curriculum that teaches developers everything that they need to know about software architecture with ColdFusion. If you still want to know more, are interested in finding out more about the class, book, or CFUnited session, or you have some suggestions or advice to offer regarding the topic, please don't hesitate to send me an e-mail at simon@horwith.com.
Published April 13, 2005 Reads 11,736
Copyright © 2005 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Simon Horwith
Simon Horwith is the CIO at AboutWeb, LLC, a Washington, DC based company specializing in staff augmentation, consulting, and training. Simon is a Macromedia Certified Master Instructor and is a member of Team Macromedia. He has been using ColdFusion since version 1.5 and specializes in ColdFusion application architecture, including architecting applications that integrate with Java, Flash, Flex, and a myriad of other technologies. In addition to presenting at CFUGs and conferences around the world, he has also been a contributing author of several books and technical papers.
- Oracle To Keynote Cloud Computing Expo
- Contrary Opinion: Why Silverlight is Good for Adobe
- Analytics for Adobe Air Applications
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Eval JavaScript in a Global Context
- Fig Leaf Software to Exhibit at Government IT Conference & Expo
- Is Microsoft as Free as Open Source?
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- The Planet Named “Bronze Sponsor” of Cloud Computing Expo
- Adobe Reader Sued
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Adobe Enters Cloud Computing with LiveCycle
- Oracle To Keynote Cloud Computing Expo
- Social Media Terrorists
- Adobe Flash Media Server on iPhone
- Contrary Opinion: Why Silverlight is Good for Adobe
- Adobe Flash Based GetJar Surpasses a Half Billion Downloads
- Adobe ColdFusion 9 and ColdFusion Builder Public Betas Now Available
- Adobe Tries Commercializing Its Online Software
- Adobe Open Sources Flash Initiatives
- The Next Programming Models, RIAs and Composite Applications
- Where Are RIA Technologies Headed in 2008?
- Constructing an Application with Flash Forms from the Ground Up
- AJAX World RIA Conference & Expo Kicks Off in New York City
- CFEclipse: The Developer's IDE, Eclipse For ColdFusion
- Personal Branding Checklist
- Adobe Flex 2: Advanced DataGrid
- Has the Technology Bounceback Begun?
- Building a Zip Code Proximity Search with ColdFusion
- i-Technology Viewpoint: We Need Not More Frameworks, But Better Programmers



































