An Architect's View

CFML, Clojure, Software Design, Frameworks and more...

An Architect's View

FW/1 and Mura

August 11, 2010 · 11 Comments

I spent an afternoon with the extremely smart, creative folks at Blue River Interactive today, the minds behind the wonderful Mura Content Management System. We mostly focused on the FW/1 Plugin Template they've created, looking at ways to make it easier to use for Mura developers.

The end result was a couple of enhancements, one suggested by Steve Withington (thank you!) and one suggested by Matt Levine of Blue River, and a new version of the FW/1 Plugin Template on the Mura App Store (version 1.1). If you're building plugins for Mura and you're looking for a little structure, take a look at this plugin. The familiar $ object that provides access to the whole Mura ecosystem is now available directly in FW/1 views and layouts so the techniques you've learned for working with Mura in display objects can be applied to plugins you create with FW/1. Similarly, techniques you've learned for FW/1 - such as relying on the buildURL() and redirect() APIs - will work seamlessly in the Mura plugin, both in the admin and in user-facing pages.

Tags: coldfusion · fw1 · oss

11 responses so far ↓

  • 1 jbuda // Aug 11, 2010 at 12:46 AM

    Excellent news Sean. I have been working with the current Plugin Template on the Mura Store and found it very easy to work with and get something up and running quickly.
  • 2 Grant Shepert // Aug 11, 2010 at 7:42 AM

    Good stuff, Sean. Just curious ... were the enhancements to FW/1 itself, or to Mura and the FW/1 Plugin?

    Also, I couldn't see any changes in the way $ was called, except that you used rc.$ instead of rc.Mura.$. Just wanted to make sure I didn't miss something there.
  • 3 Grant Shepert // Aug 11, 2010 at 8:43 AM

    Oh, and just discovered an inexplicable issue: for multiple FW/1-based display objects on a single Mura page, I had to add this to the top of the "doEvent()" function.

          <cfif structKeyExists(request,"serviceExecutionComplete")>
             <cfset structDelete( request, "serviceExecutionComplete" )>
          </cfif>

    This, even though the structDelete clearly exists at the bottom (i.e. exactly like the new 1.1 version). Strangeness.
  • 4 Steve Withington // Aug 11, 2010 at 1:00 PM

    @Sean,
    Thanks for taking the time to get this setup. I really do think this will help other developers attempting to integrate FW/1 with other applications (not just Mura).

    You rock!
  • 5 Bob // Aug 11, 2010 at 1:24 PM

    Perhaps now you can teach them the fine art of var scoping their CFCs...
  • 6 Sean Corfield // Aug 12, 2010 at 4:51 PM

    @Grant, there were changes to *both* FW/1 and the Mura plugin (which includes that updated version of FW/1).

    Can you email me details about service execution complete stuff - a blog isn't really the place for 'support' questions?

    @Bob, var is needed in singletons to avoid thread safety issues - if a CFC is created per request, it wouldn't need var declarations. Sounds like you have an issue you need to take up with Mura directly - not on this blog?
  • 7 Pat Santora // Aug 14, 2010 at 8:17 AM

    Fantastic stuff! This will make Mura that much more flexible.
  • 8 Matt Levine // Aug 17, 2010 at 9:59 AM

    Just an update, I recently added a couple new methods to the fw1 adapter to create better thread safety. They are preserveInternalState() and restoreInternalState(). They strip out all fw1 variables from the request scope and then put them back in.

    <cfset variables.preserveKeyList="context,base,cfcbase,subsystem,subsystembase,section,item,services,action,controllerExecutionStarted">

    <cffunction name="preseveInternalState" output="false">
          <cfargument name="state">
          <cfset var preserveKeys=structNew()>
          <cfset var k="">
          
          <cfloop list="#variables.preserveKeyList#" index="k">
             <cfif isDefined("arguments.state.#k#")>
                <cfset preserveKeys[k]=arguments.state[k]>
                <cfset structDelete(arguments.state,k)>
             </cfif>
          </cfloop>
          
          <cfset structDelete( arguments.state, "serviceExecutionComplete" )>
          
          <cfreturn preserveKeys>
       </cffunction>
       
       <cffunction name="restoreInternalState" output="false">
          <cfargument name="state">
          <cfargument name="restore">
          
          <cfloop list="#variables.preserveKeyList#" index="k">
                <cfset structDelete(arguments.state,k)>
          </cfloop>
          
          <cfset structAppend(state,restore,true)>
          <cfset structDelete( state, "serviceExecutionComplete" )>
       </cffunction>

    @bob If var scoping is an issue that hinders your adoption of Mura I would appreciate it if you would run varscoper on the the latest build and report back in the Mura forum.
  • 9 Sean Corfield // Aug 17, 2010 at 10:38 AM

    @Matt, could you explain why those are useful in the context of the FW/1 adapter?

    There are no thread safety issues with FW/1 itself (at least, by design, its behavior is intentional). What does your state manipulation achieve?
  • 10 Matt Levine // Aug 17, 2010 at 11:25 AM

    The thread safety has to do with the fact that when using FW/1 as a sub app to Mura you may have more than one FW/1 invocation firing in same request. So you need to make sure that all the data specific to the previous FW/1 invocation are cleaned up before starting a new FW/1 invocation and restore after.

    It become particularly important when binding custom Mura events to FW/1 actions. The custom event can be announced by other FW/1 based eventHandlers/displayObjects. This creates a situation where the second second FW/1 inovation happens inside of the first.

    So it's not a FW/1 issue, it's a using FW/1 as a Mura sub application framework issue.
  • 11 Sean Corfield // Aug 18, 2010 at 10:54 AM

    @Matt, thanks for the clarification. I can see where FW/1 could get confused in the situations you describe (since it was designed to handle the entire request, not be invoked multiple times during a single request).

Leave a Comment

Leave this field empty: