Software System Construction:Business logic
10.4 Business logic
10.4.1 Using ColdFusion to publish a database on the Internet
Allaire's ColdFusion is used to implement the functionality of the application. ColdFusion is a scripting language that involves writing tags that are then converted to HTML for delivery to the client browser. In simple terms, any page that has the extension '.cfm' will be intercepted by the ColdFusion Application Server and processed on the server before being handed back to the web server as straight HTML for return to the client (figure 10.7). In ColdFusion, web pages with the extension .cfm are known as ColdFusion templates. There is a potential for confusion between a ColdFusion template – which is used to generate HTML content for delivery to the user browser – and a DreamWeaver template, which is used by the web site designer to create a design layout for the 'real' web pages that will be served up to a client.
To give a flavour of the power of ColdFusion, we will list the contents of the table tblProductionType in a web browser using the MS Access query qryProduction Type. The ColdFusion template is a mixture of standard HTML and ColdFusion tags. These tags are processed on the server to generate pure HTML that is served up to the client browser. Assume that the ColdFusion template, listprodtype.cfm, is as follows:
<html> <head> <title>Production Type list</title> </head> <body> <cfquery name="productionTypeList" datasource="theatre"> select * from qryProductionType order by fldProductionType </cfquery> <h1>ProductionType List</h1> <cfoutput query="productionTypeList"> #fldProductionTypeID#: #fldProductionType#<br> </cfoutput> </body> </html>
The ColdFusion tags used in this example are <CFQuery> and <CFOutput>; one executes a SQL statement to query the database and the other presents the results back to the browser. The <CFQuery> tag accesses the MS Access database (theatre.mdb) via the parameter 'datasource'. The datasource 'theatre' is established and tuned using the ColdFusion administrator interface, keeping the code free from the details of database connectivity. The <CFOutput> tag cycles through the records returned by the query replacing the fields surrounded by '#' characters with the actual database content. To achieve the same result with Active Server Pages (ASP) would require a lot more code – explicit code to loop through the records and provision of full details of the database connection. The HTML delivered to the browser by the server and the browser output are shown in figure 10.8.
Queries and the three ANSI three-level architecture model
By defining a query in MS Access it is possible to achieve a degree of insulation from the underlying database structure. A general rule is to use queries (known as views in MS SQL Server) so that changes to the underlying tables do not necessarily result in changes to the business logic. This preserves the ANSI three-level architecture where the external or user view (implemented as queries in Access), the conceptual view (implemented as tables in Access), and the internal or physical view of the database (implemented using the JET database engine in MS Access) are kept separate. Users, who can be people and programs, should only access the database via a user view, i.e., using a query in MS Access. If one user is allowed to see the details of employees but not their salaries then their view will not contain this field – it is as though this field does not exist in the database. Another user might be able to access all the employee details, including salary, but only for box office staff. The three-level model also means that changes to the physical storage of data in the DBMS do not lead to changes in the database tables. Furthermore, changes to the conceptual view (the Access tables) do not necessarily mean that the programmes using that view need to be rewritten – it may be sufficient to rewrite the query.
This three-level database model should not be confused with the three-tier application architecture adopted for the Ticket Manager application. The business logic tier of the application architecture should only access the database via user views, i.e., MS Access queries. We would therefore expect all of our SQL statements in ColdFusion templates to refer to MS Access query objects (prefixed 'qry') and never to MS Access base tables (prefixed 'tbl'). This is another good reason for implementing and adhering to naming standards.
10.4.2 Developing ColdFusion components for the business logic
In the technical design we proposed that the operations of each of the classes would be implemented using components, a new feature introduced in ColdFusion MX. For example, to maintain the production types business objects we will build a component called productionType that is stored in the file productiontype.cfc and will support the methods 'add', 'change', 'delete', and 'get'.
The component will implement the four methods as functions:
add a new record is added to the database with value of fldProductionType set to the argument prod Type change the value of fldProductionType in the record with fldProductionTypeID equal to the argument prodTypeID is changed to the value of prod Type delete the record with a fldProductionTypeID value equal to the value of the argument prodTypeID is deleted get a query containing all the records in the qryProductionType view is returned In figure 10.9 the form completed by the user to add a new type of production is shown, in this case a new type called 'Stand-up Comedy' is to be added. On clicking submit, the template maintainprodtype.cfm is invoked. This template calls the component productiontype.cfc using the method 'add' and then uses the method 'get' to list the updated contents of the database.
In the productiontype.cfc component there are four functions, each of which is defined by the <CFFunction> tag. Depending on the method called, different SQL statements are executed by the productionType component. To add a new record the SQL Insert statement is executed, to change a record SQL Update is executed, to delete a record SQL Delete is used, and to get a set of records the SQL Select statement is used. Each of the functions requires different inputs, which are specified using <CFArgument>. For example, to delete a production type from the database only the value of the fld Production Type ID to be removed from the database need be passed to the function. Three of the functions – add, change, delete – alter the contents of the database and could be written such that they do not return a result to the caller. In the code listing above, they actually return a Boolean value, which is set to TRUE to indicate the operation on the database was completed. Additional code should be added to the component to check that the database operation was indeed successful, to catch any errors, and in the event of a problem, return a Boolean value of FALSE to the caller. The 'getProdTypes' function is slightly different because it does not alter the database contents but returns a result of type 'query' – a recordset containing the results of running the SQL Select statement.
The code listing for component productiontype.cfc is as follows:
<!--- Comment: ColdFusion Component to manage production type data ---> <cfcomponent> <!---Comment: function to add a new production type to the database. ---> <cffunction access="public" name="addProdType"output="false" returntype="boolean"> <cfargument name="prodType" type="string"required="true" default=""> <cfquery datasource="theatre"> Insert into qryProductionType (fldProductionType) values ('#prodType#') </cfquery> <cfset resultAdd=TRUE> <cfreturn resultAdd> </cffunction> <!--- Comment: function to delete a production type to the database ---> <cffunction access="public" name="deleteProdType" output="false" returntype="boolean"> <cfargument name="prodTypeID" type="numeric" required="true" default=""> <cfquery datasource="theatre"> Delete from qryProductionType Where fldProductionTypeID = #prodTypeID# </cfquery> <cfset resultDelete=TRUE> <cfreturn resultDelete> </cffunction>
<!--- Comment: function to change a production type from the database ---> <cffunction access="public" name="changeProdType" output="false" returntype="boolean"> <cfargument name="prodTypeID" type="numeric" required="true" default=""> <cfargument name="prodType" type="string" required="true" default=""> <cfquery datasource="theatre"> Update qryProductionType Set fldProductionType = '#prodType#' Where fldProductionTypeID = #prodTypeID# </cfquery> <cfset resultChange=TRUE> <cfreturn resultChange> </cffunction> <!--- Comment: function to retrieve recordset of all production types ---> <cffunction access="public" name="getProdTypes" output="false" returntype="query"> <cfquery datasource="theatre" name="productiontype"> select * from qryProductionType order by fldProductionType </cfquery> <cfset outputData="#productiontype#"> <cfreturn outputData> </cffunction> </cfcomponent>
To invoke a method in a component from a ColdFusion template (such as maintainprodtype.cfm) the <CFInvoke> tag is used. For example, to add a new production type the following code can be used:
<cfinvoke component="theatremx.cfc.productiontype" method="addProdType" returnvariable="addSuccess"> <cfinvokeargument name="prodType" value="Stand-up comedy"> </cfinvoke>
In practice, the value of the prodType argument will be retrieved from a form (as in figure 10.9) and a variable then passed to the component:
<cfinvokeargument name="prodType" value=''"form.prodType">"
Figure 10.9: Form for collecting the new production type and the form result To obtain a recordset containing all the production types in the database the calling ColdFusion template invokes the function 'getProdTypes':
<cfinvoke component="theatremx.cfc.productiontype" method="getProdTypes" returnvariable="prodTypeRecSet"> </cfinvoke>
The recordset returned in prodTypeRecSet is then used in conjunction with a <CFOutput> tag to display details of the production type query in the user browser.
If all applications use components to interface with the business data layer for add, change, delete, and read operations then changes to the business logic, such as the seat allocation algorithm can be made, secure in the knowledge that the change will be implemented in all areas of TicketManager and any other Internet applications that use the tag. For example, the seat allocation routine contains a considerable number of lines of code, but to invoke it from the user presentation layer is simple:
<cfinvoke component="theatremx.cfc.performance" method="findSeats" returnvariable="allocatedSeatList"> <cfinvokeargument name="partTheatre" value="#form.partTheatre#"> <cfinvokeargument name="performance" value="#form.performance#"> </cfinvoke>
The calling template of the method 'findSeats' simply specifies the identifiers for the user-selected performance and part of theatre. When the invocation tag is run the calling template is returned with a comma-delimited list containing the IDs of the seat numbers that have been allocated. The seats can now be presented to the user for confirmation of purchase.
10.4.3 State management
The ticket booking system requires us to be able to manage the state of the clients. There is no easy way for a server to manage the state of the client sessions, due to the inherent statelessness of client and server communications on the Internet. Every client request stands on its own and has no knowledge of prior interactions. This means that a variable set during one request, such as the productionID of the production a customer wants to find seats for is not available to the next processed request (e.g., the next web page). There are three main ways of addressing state on the Internet: URL parameters, cookies, and session variables. The TicketManager application will make use of all three approaches.
URL parameters and form fields
The simplest way of remembering state is to pass parameters between pages using the URL string, for example the web page productionlist.cfm might have the following link:
http://www.wisdm.net/theatre/performancelist.cfm?productionID=6
The value of the production is now accessible to the ColdFusion page performancelist.cfm, which can display the performances associated with the production where the production ID is equal to 6. This is simple and convenient and works best where the navigation is fixed, as is the case when users navigate from productionlist.cfm to performancelist.cfm. Form fields can also be used to pass values between pages and hidden form fields can be used to pass parameters from page to page to page. All of these techniques are used in the TicketManager application.
Cookies
Passing parameters from page to page works fine, but it becomes cumbersome, particularly where a parameter has to be passed through numerous intermediate pages. It would be nice to store the parameter somewhere so that all the pages invoked afterwards can access the parameter. One way of doing this is to set a cookie. A cookie is a variable that is stored on the client's browser and accessible by the web server. Cookies are often used to keep track of visitors, to know who they are and where they have been. However, not all browsers support cookies and some users will not allow cookies to be written to their browsers due to concerns about how the data collected will be used, and concerns about possible breaches of security.
In the theatre booking system cookies will be used to write the customer ID to the client browser of any visitor who has bought a ticket or has registered for membership. This will allow the application to identify and welcome back previous customers. When the user visits the site, if a cookie is found in their browser then the customer id is looked up in the database and a message can be displayed such as 'Welcome back Fred Jones!'. Marketing can now be targeted on a one-to-one basis. We might look at the purchase history of the customers and make them a special offer based on their theatre-going preferences. This is possible because every customer who purchases a ticket is set up in the Customer table and the cookie allows us to invisibly recognize a returning customer. This is what supermarket loyalty cards attempt to do, but they rely on the customer having their card with them – on the web it is more like slipping a token into their pocket as they leave the supermarket. We can do the same thing for members and therefore recognize them regardless of whether or not they log in. Of course, if they access the Theatre web site from a different machine, say from a CyberCafe, then the cookie will not be available and we will not be able to recognize the customer unless they log in.
Session variables
A session can involve many executable web pages and various interactions with the business logic. For example, one customer might carry out multiple searches for productions and available seats and could be allocated seats at many different performances before finally deciding to make a confirmed booking – or they might just wander off leaving the seats allocated but unpaid for. Cookies are one way of achieving the processing of a use case, another is to use session variables. The primary difference between a cookie and a session variable is that the session variable is held on the server rather than on the client's browser. The sequence diagram in figure 9.11 (chapter 9) shows the creation of a session variable following the allocation of seats. A session variable is used to hold details of the seat booking, including the seat numbers that have been allocated. Regardless of which pages the customer visits on the theatre site, or even if they leave the site altogether, the session variable will still contain details of their provisional booking. Session variables do not last forever and are assigned a timeout – in the TicketManager application they are set to timeout after 10 minutes of inactivity.
10.4.4 Database transactions
As noted in technical design, a logical transaction is often made up of a number of database updates. To add a ticket transaction involves adding a customer, a ticket transaction, and one or more seat at performance rows. All updates should succeed or the whole transaction fail. Industrial strength databases, such as Microsoft SQL Server and Oracle, have transaction support and rollback built into them. ColdFusion has a tag <CFTransaction> that can give this facility to any database, including MS Access.
Using the tag, the transaction can be rolled back if any part of it fails, thus leaving the database in a consistent state.
Comments
Post a Comment