Posts with the tag 'example'


Implementing Master Page concept in ColdFusion

One of the functionality I like in asp.net platform is the master page concept, it really helpful to keep the layout clean and gives really good control to developer in terms of placement of content/data on the rendered page. Having worked on aps.net side of it, I figured it’s fairly easy to implement the similar concept in ColdFusion, let me first explain what master page is.
“Master pages allow you to create a consistent layout for the pages in your application. A single master page defines the look and feel and standard behavior that you want for all of the pages (or a group of pages) in your application. You can then create individual content pages that contain the content you want to display. When users request the content pages, they merge with the master page to produce output that combines the layout of the master page with the content from the content page.” Reference : http://msdn.microsoft.com/en-us/library/wtxbf3hh.aspx (can read more about master page..)

How does master page functionality work

a) Create a master page
You need a master page (i.e. the template) with global layout of your web application, there can be multiple templates if you want different look and feel for different section or can have just one global master page for the entire web app, part of the template you will have to also put in placeholder that can be updated by the developer that will be creating functionality for individual pages.

b) Create content page
Content page is the actual page that gets shown to the user; it’s the combination of template + the content relevant to that page. In this page the developer fills in the master page placeholder with page relevant content and there for have full control over what gets rendered to the end user.

Why is master page required in ColdFusion application?

Before I even answer this question, lets walk through the scenario of how page template are created in most of the ColdFusion application, normally the header and footer or other section gets broken into separate file like Header.cfm, footer.cfm etc etc, and the individual content page like index.cfm will include header.cfm on top and then add some html code for the page and finally include footer.cfm something like this.

<cfinclude template="header.cfm"/>
Some content,  static, via db or other means.
<cfinclude template="footer.cfm"/>

So what’s the big deal?

Normally this is not a problem when you start with the project, but slowly and slowly as the number of pages for the site increases you start to realize that header and footer has to change on page by page basis, and you start introducing variables and start having conditional logic in your header and footer pages, or another situation can be that for some special pages you need to add css or javascript because those pages are doing special ajax stuff, but you don’t want to add that to header, because it will get included for all pages and that will slow down the site, so basically start adding the css and javascript withing the content page and after some time your page looks like javascript and css all over the place, plus your header and footer files have ton’s of conditional logic.
Check out http://www.sys-con.com/ and perform view source, scroll through the html and see how css and javascript is pretty much all over the page, and not consolidated in header section, where it should be right?

How does master page help?

By using master page you get multiple benefits,

  • don’t have to break the layout in multiple files like the header.cfm and footer.cfm earlier
  • the layout logic is clean and does not have to be conditional
  • by providing placeholder at proper places you give the developer an opportunity to put in page related content
  • master page maintains the rendered document structure and can help you comply with w3c standards
  • Other benefits are also possible -)

How to implement Master page in coldfusion

Along with this entry I have also posted sample code, that shows standard way of using template and how that can be implemented as master page in coldfusion. The examples are self explanatory but to provide brief overview the concept is to first define master page somewhat like this (just an example).

Download Code

  1. <cfoutput>
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  3. <html>
  4. <head>
  5. <title><cfif isDefined("variables.master_page_title")>#master_page_title#<cfelse>Free Css Layout 1</cfif></title>
  6. <meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
  7. <link rel="stylesheet" type="text/css" href="css/style.css" />
  8. <cfif isDefined("variables.master_page_javascript")>#variables.master_page_javascript#</cfif>
  9. <cfif isDefined("variables.master_page_css")>#variables.master_page_css#</cfif>
  10. </head>
  11. <body>
  12. <div id="container">
  13. <div id="header"><h1><a href="http://www.free-css.com/free-css-layouts.php">Free CSS Layouts</a></h1></div>
  14. <div id="wrapper">
  15. <div id="content">
  16. <cfif isDefined("variables.master_page_body")>#variables.master_page_body#</cfif>
  17. </div>
  18. </div>
  19. <div id="navigation">
  20. <p><strong>Navigation Here</strong></p>
  21. <ul>
  22. <li><a href="http://www.free-css.com/">Free CSS Templates</a></li>
  23. <li><a href="http://www.free-css.com/free-css-layouts.php">Free CSS Layouts</a></li>
  24. </ul>
  25. </div>
  26. <div id="extra">
  27. <p><strong>More stuff here.</strong></p>
  28. <p>sit malesuada lacus pellus parturpiscing. Pellenterdumat maecenatoque cras a magna nibh et quis diam ames et. Laoremvolutpat ac dolor eget eget temper lacus vestibus velit lacus venean. Magnaipsum tellus morbi leo aliquat nulla convallis pellentesque.</p>
  29. </div>
  30. <div id="footer">
  31. <p>Footer</p>
  32. </div>
  33. </div>
  34. </body>
  35. </html>
  36. </cfoutput>

Important thing to note is the cfif tag followed by the variable.name , basically these are the values that can be supplied by individual page developer and that gets merged when final page is rendered

The content page will look like this

  1. <cfsavecontent variable="variables.master_page_body">
  2. <p><strong>Content here.</strong></p>
  3. <p>Sapibulumnibh phasellus nulla egestibulum enim pretium elit tincidunt estiquam ultrisque donectetur. Sedcondimentumsan odio hendrerit proin vitae dignis nibh ac justo id congue. Amesintesque vel curabitae volutpat donec alique nasceleifendimentesque montesque rhoncus quis eros. Vestnunc nonummy</p>
  4. <p>Montegeraliquam sed pede in cursus praesenec vestas rhoncus wisi at wisi. Condisseloborttis enim et ipsum mauristie id felit adipiscipit ac auctortorttitor sempor. Vitantesqueat sempus non sed et mus sit vivamus purus netus hendiment. Pretiuma diam et id tempus dolor por wisi sed volutpat facilisi.</p>
  5. <p>Wisiet sus adipit phasellentum elit condissim consecteturpiscing sapien vivamus et congue. Utvel tris quismod cursus liberos elit nisse curabitur tur parturpis tellenterdum. Semperligula curabitae tellentesque nulla trices vestas ristibulum id justo auctor facinia. Natisdonec consequat nibh pellus.</p>
  6. <p>Vestibusodio euisque id elerisus lacus tincidunt sit malesuada lacus pellus parturpiscing. Pellenterdumat maecenatoque cras a magna nibh et quis diam ames et. Laoremvolutpat ac dolor eget eget temper lacus vestibus velit lacus venean. Magnaipsum tellus morbi leo aliquat nulla convallis pellentesque.</p>
  7. </cfsavecontent>

Another example

  1. <cfset variables.master_page_title="updated page..">
  2.  
  3. <cfsavecontent variable="variables.master_page_javascript">
  4. <script language="javascript" src="http://www.cachefile.net/scripts/prototype/1.6.0.2/prototype.js" type="text/javascript"></script>
  5. <script language="javascript">
  6. Event.observe(window, 'load', function() {
  7. alert("page loaded..");
  8. });
  9. </script>
  10. </cfsavecontent>
  11.  
  12. <cfsavecontent variable="variables.master_page_css">
  13. <style type="text/css">
  14. .style1 {font-size:10px;}
  15. </style>
  16. </cfsavecontent>
  17.  
  18. <cfsavecontent variable="variables.master_page_body">
  19. <p><strong>Content here.</strong></p>
  20. <p>Sapibulumnibh phasellus nulla egestibulum enim pretium elit tincidunt estiquam ultrisque donectetur. Sedcondimentumsan odio hendrerit proin vitae dignis nibh ac justo id congue. Amesintesque vel curabitae volutpat donec alique nasceleifendimentesque montesque rhoncus quis eros. Vestnunc nonummy</p>
  21. <p>Montegeraliquam sed pede in cursus praesenec vestas rhoncus wisi at wisi. Condisseloborttis enim et ipsum mauristie id felit adipiscipit ac auctortorttitor sempor. Vitantesqueat sempus non sed et mus sit vivamus purus netus hendiment. Pretiuma diam et id tempus dolor por wisi sed volutpat facilisi.</p>
  22. <p>Wisiet sus adipit phasellentum elit condissim consecteturpiscing sapien vivamus et congue. Utvel tris quismod cursus liberos elit nisse curabitur tur parturpis tellenterdum. Semperligula curabitae tellentesque nulla trices vestas ristibulum id justo auctor facinia. Natisdonec consequat nibh pellus.</p>
  23. <p>Vestibusodio euisque id elerisus lacus tincidunt sit malesuada lacus pellus parturpiscing. Pellenterdumat maecenatoque cras a magna nibh et quis diam ames et. Laoremvolutpat ac dolor eget eget temper lacus vestibus velit lacus venean. Magnaipsum tellus morbi leo aliquat nulla convallis pellentesque.</p>
  24. </cfsavecontent>

Here you can see the content page have to supply the value to master page placeholder , also to note is that content page does not have to supply all the values, it can omit what it does not care about (that’s why the master page had conditional if logic)

The actual magic of merging master page and template page happens in the onRequestEnd.cfm file where this file basically removes all the previous content and based on setting loads the appropriate template file! Download Code to view files

Conclusion

If the master page approach is used in your web application development, you will end up getting multiple benefits

  • Single template file (though you can multiple template file for certain section of site, all you have to do is create another template file and define a variable on your content page like this
    <cfset request.master_page_template = "the new template/master page name"/> )

  • Using master page you can get rid of empty white space on your page (specially on the very top of generate html page )
  • Master page gives the content page developer flexibility on how to fill in the template
  • Generated html page is clean
  • Don’t have to deal with multiple include files
  • Overall it’s easy to use.

[Update : Most of the Coldfusion MVC framework provides template concept - but the implementation varies]

6 comments December 19th, 2008

Strategy Design Pattern in Coldfusion

In this blog post I will demonstrate the practical use of strategy design pattern in ColdFusion and discuss other possibilities.

So what is Strategy Design Pattern?
Wikipedia : “In computer programming, the strategy pattern (also known as the policy pattern) is a particular software design pattern, whereby algorithms can be selected at runtime.
Gang of four : “Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

So from the various descriptions it’s clear that this pattern can be used in the situation where there is possibility of having difference/multiple calculation and the application has to choose the right one on the fly.

I am going to use a scenario to build the case on why and how this pattern should be used.

Scenario:

Let’s say there is a web application which has multiple developers working on it, or have multiple teams working on independent section of the application, in such sort of application its fundamental to have core set of components that the developer use and there is also a possibility that they may be used across multiple applications. In such sort of scenario its inherent that core component be stable and least amount of changes should be done on the core components (i.e. cfc’s ) to avoid large scale impacts to other modules/developers.

So let’s say one of the core components that we have is the Customer.cfc it has some properties and also methods which get used by the appropriate section of the web applications


example1.jpg

<cfcomponent name="Customer" output="false">
  <cfscript>
    this.name = "";
    this.address = "";
    this.customerType = 0;
    this.balanceDue = 0;
  </cfscript>
</cfcomponent>
<!--- 
  ideally all the attributes should be in variables scope and have a get/set method defined, 
  but i am skipping that portion, so that i can focus on strategy pattern, and to have 
  less code :-) 
--->

There came a request for business to also start storing the latitude and longitude of customer location in the database and it was decided that we are going to use Google’s reverse lookup service, everybody agreed and the core Customer.cfc got updated to
example2.jpg

<cfcomponent name="Customer" output="false">
  <cfscript>
    this.name = "";
    this.address = "";
    this.customerType = 0;
    this.balanceDue = 0;
    this.latitude = 0;
    this.longitude = 0;
  </cfscript>
  
  <cffunction name="reverseLookup">
    <!--- 
      perform the reverse geocode with google  and return the values back as a string
      and also update the latitude and logitude attribute
    --->
    <cfreturn "">
  </cffunction>
</cfcomponent>

Here you can see two new properties were added and a method was added to perform the reverse lookup.

This worked fine, until business came back and said that they are not pleased with Google’s service and want to use yahoo, the simpler solution would be just remove the Google specific code and replace it with yahoo code, but the architect decided why not have both in place, who know the business may change their mind, so the code updated to.

example3.jpg

<cfcomponent name="Customer" output="false">
  <cfscript>
    this.name = "";
    this.address = "";
    this.customerType = 0;
    this.balanceDue = 0;
    this.latitude = 0;
    this.longitude = 0;
  </cfscript>
  
  <cffunction name="reverseLookup">
    <cfargument name="serviceID" type="numeric" required="true">
    <cfif serviceID EQ 1>
      <!--- google code--->
    <cfelseif serviceID EQ 2>
      <!--- yahoo code--->
    </cfif>
    <cfreturn "">
  </cffunction>
</cfcomponent>

As you can see the core component introduced the notion of serviceID, where the developers or consumer of this component has to supply the service ID i.e. yahooID or googleID. The change was made but it involved much pain because all the developers has to be notified about it and also the other applications that were using the component had to made updates because the interface for the core component got changed.

Now after some time, the business came up with another suggestion they had found this database that can be bought which has all the required data to perform the reverse lookup without going to any third party and wanted the development team to implement it. To accommodate this request the core component had to be again updated, with an additional IF condition
<cfcomponent name="Customer" output="false">
  <cfscript>
    this.name = "";
    this.address = "";
    this.customerType = 0;
    this.balanceDue = 0;
    this.latitude = 0;
    this.longitude = 0;
  </cfscript>
  
  <cffunction name="reverseLookup">
    <cfargument name="serviceID" type="numeric" required="true">
    <cfif serviceID EQ 1>
      <!--- google code--->
    <cfelseif serviceID EQ 2>
      <!--- yahoo code--->
    <cfelseif serviceID EQ 3>
      <!--- db code--->
    </cfif>
    <cfreturn "">
  </cffunction>
</cfcomponent>

As you can see in every situation the core component gets effected, i.e. any time a new vendor is found the core component has to be updated with additional IF logic, which means the core component has to be touched every time and developed team really does not want to do that because of downside impact that may happened if a bug got introduced during the change.

How does Strategy Pattern Solves the above problem?

Strategy Pattern is the perfect solution for the above mentioned scenario, where first of the the calculation/algorithm (i.e. the reverse geocoding) part of the code, gets split into a component of its own, so there will be a .cfc file for each of the reverse geocoding i.e. googleReversGeocoding.cfc , yahooReversGeocoding.cfc and databaseReversGeocoding.cfc and they all will inherit a single interface to perform decoding

example4.jpg
example5.jpg
IReverseLookup.cfc

<cfinterface name="IReverseLookup">
  <cffunction name="decode" returntype="string">
    <cfargument name="address" type="String" required="true">
  </cffunction>
</cfinterface>

GoogleReverseLookup.cfc

<cfcomponent name="GoogleReverseLookup" implements="IReverseLookup">
  <cffunction name="decode" returntype="String">
    <cfargument name="address" type="String" required="true">
    <!--- 
      make calls to google 
      and return the data
    --->
    <cfreturn "1929202.111, 292920.211">
  </cffunction>
</cfcomponent>

YahooReverseLookup.cfc

<cfcomponent name="YahooReverseLookup" implements="IReverseLookup">
  <cffunction name="decode" returntype="String">
    <cfargument name="address" type="String" required="true">
    <!--- 
      make calls to yahoo
      and return the data
    --->
    <cfreturn "0119182781.111, 5111192929.211">
  </cffunction>
</cfcomponent>

DatabaseReverseLookup.cfc

<cfcomponent name="DatabaseReverseLookup" implements="IReverseLookup">
  <cffunction name="decode" returntype="String">
    <cfargument name="address" type="String" required="true">
    <!--- 
      make calls to Database
      and return the data
    --->
    <cfreturn "000002221, 0028289.857">
  </cffunction>
</cfcomponent>

DatabaseReverseLookup.cfc

<cfcomponent name="Customer" output="false">
  <cfscript>
    this.name = "";
    this.address = "";
    this.customerType = 0;
    this.balanceDue = 0;
    this.latitude = 0;
    this.longitude = 0;
  </cfscript>
  
  <cffunction name="reverseLookup">
    <cfargument name="reversLookupStrategy" type="IReverseLookup" required="true">
    <cfreturn reversLookupStrategy.decode(this.address)>
  </cffunction>
</cfcomponent>

example1.cfm

<cfset customer = CreateObject("component", "Customer")>
<cfset customer.address = "410 washington Street, Greely, NC 10001">
<!--- set other properties --->

<!--- code wasts to use google service --->
<cfset strategy = CreateObject("component", "GoogleReverseLookup")>
<cfoutput>#customer.reverseLookup(strategy)#<br></cfoutput>

<!--- code wasts to use yahoo service --->
<cfset strategy = CreateObject("component", "YahooReverseLookup")>
<cfoutput>#customer.reverseLookup(strategy)#<br></cfoutput>

<!--- code wasts to use database service --->
<cfset strategy = CreateObject("component", "DatabaseReverseLookup")>
<cfoutput>#customer.reverseLookup(strategy)#<br></cfoutput>

So with the strategy pattern, now we will have cleaner implementation, where decoding with each vendor/service is done separately and Customer class (cfc) does not care about what vendor we are using as long the object that is being passed to it implements the IReverseLookup interface then that’s all it cares about. With this type of implementation you can add as my vendor and defined the logic in separate CFC (implement the interface) and you will never have to be updated the customer object. This way the code that is using this component can at runtime decide what strategy i.e. calculation to use without effecting the core component.

When can you use the strategy pattern be used?

a) If you have multiple components (CFC) that have structural similarity , but have different behavior (due diligence has to be done)
b) You have algorithm whose calculation can vary depending up the parameters passed to it.
c) Have excessive use of switch or if statement, and you have a desire to clear it up ?
d) You don’t want your core component to updated every time a new strategy is developed or requested.

Download Source Code

2 comments June 28th, 2008


 Subscribe in a RSS reader


CourseLookup.us - Providing course and conference information to enhance your knowledge base.

Tags

Calendar

March 2010
M T W T F S S
« Dec    
1234567
891011121314
15161718192021
22232425262728
293031  

Posts by Month

Posts by Category