Category Filtering: 'tips-tricks'

Tip of the Week: What is a Soft Reference Cache Anyway?

Tips & Tricks

CacheBox contains a number of different cache providers ranging from EHCache to Railo's Memcached.  There is also a provider implemented in ColdFusion simply called the "CacheBox Provider" and two of it's stores are the ConcurrentStore and the ConcurrentSoftReferenceStore.  You may have wondered what the "soft reference" part means and why you would want to use it.  If that's you, here's some history and explanation.  

In Java, Whether or not an object is garbage collected from the heap is dependent on whether or not it has "GC roots" or garbage collector roots.  A GC root is a reference chain in memory that ends with a root object that is exempt from garbage collection.  An example would be a thread.  It is represented by an object on the heap, but it can run forever and will never be garbage collected.  Likewise, any objects that thread has "hard" references to will also not be GC'd and anything those objects in turn have references to and so on.  So, a chain of hard references back to a GC root will keep you on the heap. 

So, why does this matter?  A JVM has a static upper bound in regards to heap space and when you're dealing with an in-process cache, you run the risk of putting so many objects in the cache that the JVM runs out of space and you get an out-of-memory error.  The concurrentStore uses a good old hard reference.  CFML only has hard references.  When you set a = b that's always a hard reference.  Java has additional types of references that can exist.  Soft references, phantom references and weak references.  They are represented as a class which sits between the referencing object and the object being referenced.  They provide a way for the referenced object to be accessed, but they don't hold a "hard" reference meaning that at any time, the garbage collector can come along, and if it needs RAM badly, it can collect any objects with a weak reference to them.  Obviously, you would only use this reference type if you were ok with your object not existing the next time you went and looked for it.

So the concurrent soft reference cache uses a concurrent hash map (like a struct, but with better performance due to it's granular internal locking and no-locking reads) which is full of soft reference objects, that in turn point to the real items you've placed in the cache.  When garbage collection runs, it has the option to remove one or all of those items from memory if it wishes.  Every time CacheBox wants to retrieve something from a soft reference store, it has ask the Java soft reference object to hand it over.  When the cache is reaped, it checks for items which have been garbage collected and don't exist any longer and expires them.  So basically, the soft reference store help protect your JVM, but it has to do a little more work to get an item.

Now, that being said, I have rarely had items be garbage collected from a softreference cache provider.  This is in part to the fact that I always monitor my heap sizes and make sure I have plenty of headroom.  

Here's some extra reading if you're still curious about the Java classes: 
http://docs.oracle.com/javase/7/docs/api/java/lang/ref/package-summary.html

And here's some more info about CacheBox providers and stores:
http://wiki.coldbox.org/wiki/CacheBox.cfm#ConcurrentSoftReferenceStore

P.S. Another way you can protect your heap is to set a JVM memory threshold in your CacheBox provider's config.  (This is only available for the internal "CacheBox" providers).  Every time CacheBox goes to set an object in the cache, it will check the percentage of free memory, and if it's too small, it will evict an item or items prior to setting the new one in based on the eviction policy and eviction count.


Tip of the Week: Superclass is Optional For Handlers, Plugins, and Interceptors

Tips & Tricks

In ColdBox, Event Handlers, Interceptors, and Plugins are represented as CFCs.  You are probably used to their signatures looking like this:

myhandler.cfc
component extends="coldbox.system.EventHandler"{}

myInterceptor.cfc
component extends="coldbox.system.Interceptor"{}

myPlugin.cfc
component extends="coldbox.system.Plugin"{}

ColdBox is very flexible though and tries to help remove as much boilerplate code for you as possible.  You can actually omit the "extends" attribute all-together from Handlers, Interceptors, and Plugins and Coldbox will automatically add Virtual Inheritance to the components at run time.  That means all the methods you're used to having available to you will still be there, but your code is light, clean, and insulated from internal class changes in the framework.

myhandler.cfc
component {}

myInterceptor.cfc
component {}

myPlugin.cfc
component {}

More info;
http://wiki.coldbox.org/wiki/Plugins.cfm#Component_Declaration
http://wiki.coldbox.org/wiki/Interceptors.cfm#How_do_they_work.3F
http://wiki.coldbox.org/wiki/EventHandlers.cfm#Constructors


P.S. You can tap into the power of Virtual Inheritance with WireBox for your own models as well.  Check out this Wiki link: http://wiki.coldbox.org/wiki/WireBox.cfm#Virtual_Inheritance


Tip of the Week: Using the AntiSamy Plugin to Clean User Input

Tips & Tricks

If your site ever displays text on the page that end users have control over, you should be concerned about XSS attacks.  This could come in the form of user comments at the bottom of an article, user-generated content, or user profile information.  In many instances, the user should never be entering any HTML and you might simply fully escape that text with HTMLEditFormat() or EncodeForHTML() as you output it.

Other times you may be dealing with a forum or message board that allows some limited markup like bold or underline, but not script or object tags, etc.  There is a very nice Java library from OWASP called AntiSamy that does just that.  AntiSamy is named after the first wide-scale XSS worm ever developed; called Samy.  This worm used malicious JavaScript embeded in MySpace profiles and to infect over 1 million accounts in a single day.

What's cool about AntiSamy is you can create different profiles that control what HTML is valid and what isn't.  This gives you complete control over what text you allow to be stored and output on your site.  Instead of escaping forbidden tags and attributes, AntiSamy removes them entirely from the string.

ColdBox has an AntiSamy plugin to let you tap into this powerful library.  In its simplest form, it looks like this:

#getPlugin("antisamy").clean("<b>Hello <script language='javascript'>alert('haxor!');</script> World</b>")#

Despite the JavaScript block in the middle of the string, the output is "<b>Hello World</b>".  As you can see, the  bold tag is benign and is left alone.  

More info here: http://wiki.coldbox.org/wiki/Plugins:AntiSamy.cfm

P.S. The ColdBox AntiSamy plugin ships with several policies such as ebay (default), myspace, slashdot, and tinymce stored as XML files in /coldbox/system/plugins/AntiSamy-lib/.  If you want to roll up your sleeves, you can even supply a policy of your own making.


Tip of the Week: Being More Productive with the Query Helper Plugin

Tips & Tricks

The Query Helper plugin is a hidden gem in ColdBox.  This plugin has a handful of super useful functions you can perform against query objects-- some of which you may have gone out of your way to write on your own in the past, or just simply lived without.  Here a brief list of my favorite functions from the Query Helper plugin that allow you to do sweet one-line manipulations of one or more query objects:

filterQuery
Pare down a result set to only the records you want.

sortQuery/sortQueryNoCase
Resort a result set on a column of your choosing.

doLeftOuterJoin
Yes, you heard right-- perform an actual left outer join with two result sets.  This alone is worth the cost of admission.

doQueryAppend
Very handy to union two result sets together quickly.

querySim
Great for mocking and testing.  Allows you to easily create a data set out of one or more lines of of pipe-delimited values.

rotateQuery
Pivots a result set so rows become columns and columns become rows.

There are more goodies in there-- take a look at the docs, or directly in /coldbox/system/plugins/QueryHelper.cfc to find the rest of them.

As usual, the Query Helper plugin can be accessed from any framework object (views, controllers, interceptor) like so:

getPlugin("QueryHelper")

and can be injected into your models like so:

property name="QueryHelper" inject="coldbox:plugin:QueryHelper";

More info here: http://wiki.coldbox.org/wiki/Plugins:QueryHelper.cfm

P.S. Remember, while these functions work great for smaller result sets, watch out for performance issues if dealing with lots of data (tens of thousands of rows).  There are some things databases are better at.


Tip of the Week: Configuring Additional CacheBox Caches

Tips & Tricks

 

Every ColdBox install comes with an instance of the CacheBox cache aggregator ready to go.  There are two caches that have to be defined: default, and template.  The former is the default provider used if you don't specify another one.  The latter provider is used internally for cached events and views.  What's cool about CacheBox as a cache aggregator is that you can configure as many named providers as you like to report and tune separate areas of your application.
 
Adding an additional named cache is easy and has virtually no overhead since most providers don't use any memory until you begin populating them with data.  Let's start by taking a look at your cache debug monitor:
http://www.mySite.com?debugMode=1&debugpanel=cache
 
 
 
Now, first off you might be wondering how the default and template cache are defined since you might not have any CacheBox-specific configuration in your app.  Don't worry-- if you don't supply any CacheBox configuration, it defaults to the settings found in /coldbox/system/web/config/CacheBox.cfc.  Once you do begin including config for CacheBox, you'll need to include the default and template caches.  
 
Where you store your CacheBox config is completely configurable, but the two most common places is a "cachebox" struct in your main /congig/ColdBox.cfc file, or in a separate file /config/CacheBox.cfc that works just like the main config.  My preference is the separate CacheBox.cfc file for organization.  You can get started by simply making a copy of the default CacheBox.cfc in your app's config directory. 
 
To add additional caches, you just need to add more nested structs to the "cachebox.caches" struct like so (I omitted all the default and template details for brevity):
 
cacheBox = {
    defaultCache = {
    ...
    },
    // Register all the custom named caches you like here
    caches = {
        template = {
        ...
        },
        // My new named cache!
        myCache = {
            provider = "coldbox.system.cache.providers.CacheBoxColdBoxProvider",
            properties = {
                evictionPolicy = "LRU",
                maxObjects = 300,
                objectStore = "ConcurrentSoftReferenceStore"
            }
        }
    }
};
 
Now, reinit your application and refresh the cache debug screen.  Your new cache name should show up in the drop down for you to view the stats and contents of it.
 
Using your new cache is also easy.  In a handler for example, the following code is all that is needed:
var myCache = CacheBox.getCache("myCache");
 
If you want to wire your new cache into a model, the following DSL will also work:
component {
    property name='myCache' inject='cachebox:myCache';
}
 
 
P.S. Don't forget to add a debugPassword setting into your app to ensure that you are the only one who can fool around with your CacheBox debug panel.  The URL only changes slightly when you have password:
http://www.mySite.com?debugMode=1&debugpass=myPass&debugpanel=cache

 


Tip of the Week: CacheBox Tuning with the Debug Panel

Tips & Tricks

 

If you use CacheBox (and if you use ColdBox to any extent, you do) it is important to inspect your cache performance from time to time.  A poorly tuned cache can bring about unexpected performance issues when your application gets under load (such as the dog-pile effect).
 
Since CacheBox is a cache aggregator that means it has the ability to wrap up multiple caches from different sources under one API.  By default, ColdBox configures two caches called "default" and "template", but you can create as many caches as you like.  One of the excellent features of CacheBox as a cache aggregator is that you get consolidated statistics on all your caches in one place.  
 
Those statistics are available programatically, but the easiest way to access them is via the web-based CacheBox debug panel.  If you have debug mode turned on, it will show up at the bottom of the request.  Even if debug mode is turned off, you can stil access the cache debug panel at any time by adding "?debugMode=1&debugPanel=cache" to the end of your URL.
 

<Click to enlarge>

 
 
There is a wealth of information on this screen including your JVM's memory usage.  After selecting a specific cache from the drop down, you can see how many items are in that particular store as well as hit/miss ratios and eviction counts.
 
The first thing to look for is signs that your cache is filling up and running out of space.  Compare the number of items in the store during a busy time to the maximum allowed  and make sure you have some breathing room.  Your  number of hits should definitely be higher than your misses.  Evictions happen when your cache is too full and has to expire items early to make room.  If you are seeing a high number of evictions and the cache is too full, increase the maximum number of objects (contingent on free memory), limit how many items your application caches, or decrease the expiration time.  
 
Remember, reaping runs every two minutes by default.  (Reaping is what actually removed expired items from the cache to make room for new ones)  Long expiration may allow you to reduce reaping frequency but short expiration times may require reaping to run more often.  Just remember, reaping locks portions of the cache's object pool when it runs so keep that in mind if your cache is very large.
 
If you're using a soft-reference store in one of the ColdBox cache providers, watch out for garbage collections.  Those happen if your heap gets so low on memory that the JVM started garbage collecting your cache items to free up space.  If that is happening, increase your heap, decrease the number of items or the size of the items in the cache, or lower the free memory threshold so evictions run sooner.
 
Another thing to consider if you're using one of the ColdBox cache providers is which eviction policy to use.  The eviction policy only kicks in when your cache is too full and items have to be kicked out prior to their normal expiration.  It's up to you to decide which items are least likely to be needed again soon based on your app's usage patterns-- the Least Recently Used, or the Least Frequently Used, etc.
 
There's a lot to consider when it comes to tuning your caches.  The best approach is making isolated changes, collecting data, performing analysis, and then repeating the cycle.  A well-tuned cache is mostly hits with far fewer misses, and naturally cleans itself through regular expirations without having to evict or garbage collect.
 
 
P.S.  Remember, if you have more than one cache, they all need to be tuned separately.

Tip of the Week: WireBox Debug Output

Tips & Tricks

 

If you've used WireBox for autowiring the CFCs in your application, you may have reached a point where you were having trouble figuring out what was going on behind the scenes.  This can be especially true if you've added auutowire metdata to a CFC, but the dependencies still aren't getting injected.
 
WireBox actually has pretty robust debug-level logging built in via LogBox that will tell you everything it is doing, but the question might be, "How do I see it?"  Wirebox's debug logging is kind of like the light in your fridge-- it's only on when you're looking at it.  
 
First, you need to have at least one LogBox appender enabled.  Depending on which application template you used, you may alread have a ColdboxTracerAppender appender configured which shows up when debug mode is on.  My favorite appender to set up an AsyncRollingFileAppender and then watch the text file with a tail program.
 
logBox = {
    appenders = {
        myAsycFile = {
            class="coldbox.system.logging.appenders.AsyncRollingFileAppender",
            properties={
                filePath=expandPath("/common/logs"),autoExpand=false
            }
        }
    }
};
 
Now, even if you already have an appender configured, you're probably not seeing any debug logs from WireBox; or any part of the ColdBox framework for that matter.  This is a good default, since ColdBox can be a bit chatty in debug mode.  The reason you're not seeing anything is because the "coldbox.system" category is turned off.  Remember that loggers in LogBox are named after the CFC they're in, and inherit logging settings in a hierarchical manner.  Look for a line of code similar to this in your config:
 
info = ["coldbox.system"]
 
This sets a maximum log level of "info" for anything logged inside of "coldbox.system".  Since all of WireBox's logs are debug level, they don't make the cut and get ignored.  To tell wirebox to start logging debug-level messages from WireBox, you can add the following line in the LogBox config:
 
debug = ["coldbox.system.ioc"]
 
After a quick reinit, LogBox will start logging debug messages from within coldbox.system.ioc (which is WireBox) to whatever appenders you have configured.  Don't forget to turn debug logs back off when you are done for performance reasons.  
 
 
P.S. You can also use environment overrides so debug messages are logged on your development machine, but not on higher environments. 

Tip of the Week: Complex ColdBox Settings

Tips & Tricks

 

One of the handy things about the ColdBox settings CFC is you can store ad-hoc settings for your application which can be retrieved or injected anywhere in your application.  
 
Remember, since your settings config is just a struct in a CFC, you aren't limited to settings which are strings.  You can store pretty much any kind of setting that will fit into a ColdFusion variable.
 
// Custom Settings
settings = {
    useSkins = true,
    servers = ['web1','web2','web3','web4'],
    skinsPath = "views/skins",
    myUtil = createObject("component","#appmapping#.model.util.MyUtility")
};
 
// Add another late addition here
settings["setMe"] = {as = 'you wish'};
 
 
P.S. Don't forget, in your environment overrides you don't need to specify the entire settings struct again.  You can override individual settings by referencing them directly.
 
function stage() {
    settings.servers = ['stage1','stage2'];
}
 

Tip of the Week: Decorating Your Controller

Tips & Tricks

 

If you've ever wanted to modify any behavior of the core ColdBox controller, you can now do so as of version 3.5.3 with the Controller Decorator feature.  This is accomplished much like the Request Context Decorator.
 
First, add a configuration setting called "ControllerDecorator" in the coldbox struct of your config file.  
 
/config/ColdBox.cfc
coldbox.controllerDecorator = "path.to.myControllerDecotrator";
 
Next, build your decorator as a CFC that extends our base coldbox.system.web.ControllerDecorator class like so.
 
/path/to/myControllerDecotrator.cfc
component extends="coldbox.system.web.ControllerDecorator"{
 
    function setNextEvent(){
        arguments.ssl = true;
        getController.setNextEvent( argumentCollection=arguments );
    }
 
}
 
That example would wrap the setNextEvent method and force it to always redirect to a secure URL.
 
 
P.S. Instead of extending a class with a super reference, the decorator pattern composes the original object in an invisible wrapper class which contains a reference to the original.  In your controller decorator, you can use the getController() method to get the original controller object.

Tip of the Week: Defaulting Values in the Request Collection

Tips & Tricks
The request collection is a struct of values which are aggregated from the FORM and URL scopes as well as remote parameters to proxy requests.  The data in your request collection is available via methods in the event object or by referencing the "rc" struct directly.
 
event.getValue('foo')
or
rc.foo
 
What do you do when you need to deal with item in the rc (or request collection) that might not exist?  Common scenarios would be check boxes that may be left blank, or optional URL parameters.  In those instances you may want to provide a default value, or simply test for the existence of the item.
 
The first thing you might think to do would be typical manipulation of the rc struct.  Remember, structs are passed by reference, so any changes made to rc in an event handler for instance, are made for the remainder of that request.
 
// Modify the rc with a default value
param name='rc.foo' default='bar';
 
// Check for the existence of a key
structKeyExists(rc,'foo')
 
// Return a default without modifying the rc
if(structKeyExists(rc,'foo')) {
    return rc.foo;
} else {
    return 'default';
}
 
Those methods will work, but there are cleaner, more consistent ways to accomplish the same end using the request context, or event object.
 
// Modify the rc with a default value
event.paramValue('foo','bar');
 
// Check for the existence of a key
event.valueExists('foo');
 
// Return a default without modifying the rc
event.getValue('foo','default');
 
Hopefully these simple but effective helper methods in the request context will make productive additions to your toolbox.  
 
 
P.S. Other useful methods: 
event.getTrimValue('foo')
event.removeValue('foo');
event.collectionAppend({foo='bar',fu='barre'});

Categories


Recent Entries

Entry Archives





ColdBox Book

book