framework

  • submit to reddit

Getting Started with ASP.NET MVC 1.0

By Simone Chiaretta and Keyvan Nayyeri

13,176 Downloads · Refcard 69 of 151 (see them all)

Download
FREE PDF


The Essential ASP.NET MVC Cheat Sheet

ASP.NET MVC is Microsofts framework for building Web applications, and this DZone Refcard will help you to get started with it. First off, youll learn how to setup your environment to work with ASP.NET MVC and how to create a web application. Then, youll get to go deeper into detail and learn about components of the framework along with the structure of the main API. The Refcard concludes with a sample of a standard operation that developers can do with ASP.NET MVC.
HTML Preview
Getting Started Oracle Berkeley DB

Getting Started with ASP.NET MVC 1.0

By Simone Chiaretta and Keyvan Nayyeri

Introduction

ASP.NET MVC is a new framework for building Web applications developed by Microsoft; it was found that the traditional WebForm abstraction, designed in 2000 to bring a “desktop-like” development experience to the Web, was sometimes getting in the way, and could not provide proper separation of concerns, so it was difficult to test. Therefore a new, alternative framework was built in order to address the changing requirements of developers. It was built with testability, extensibility and freedom in mind.

This Refcard will first explain how to setup your environment to work with ASP.NET MVC and how to create an ASP.NET MVC Web application. Then it will go deeper in details explaining the various components of the framework and showing the structure of the main API. Finally, it will show a sample of standard operation that developers can do with ASP.NET MVC.

Prerequisites

The ASP.NET MVC is a new framework, but it’s based on ASP.NET core API: in order to understand and use it, you have to know the basic concepts of ASP.NET. Furthermore, since it doesn’t abstract away the “Web” as the traditional WebForm paradigm does, you have to know HTML, CSS and JavaScript in order to take full advantage of the framework.

Installation

To develop a Web site with ASP.NET MVC, all you need is Visual Studio 2008 and the .NET Framework 3.5 SP1. If you are an hobbyist developer you can use Visual Web Developer 2008 Express Edition, which can be downloaded for free at the URL: http://www.microsoft.com/express/vwd/.

You also need to install the ASP.NET MVC library, which can be downloaded from the official ASP.NET Web site at http://www.asp.net/mvc/download.

You can also download everything you need, the IDE, the library, and also a free version of SQL Server (Express Edition) through the Web Platform Installer, available at: http://www.microsoft.com/web/.

The MVC pattern

As you probably have already guessed from the name, the framework implements the Model View Controller (MVC) pattern.

MVCpattern

The UI layer of an application is made up of 3 components:

MVC Component Description
Model The component responsible for data interactions with data storage system (typically a database) and main business logic implementations.
View The component responsible for displaying data passed from Controller to it which also renders the user interface of the site.
Controller The component that acts like a bridge between the model and the view to load data based on the request and pass them to view, or pass the data input by user to the model.

And the flow of an operation is depicted in the diagram:

  1. The request hits the Controller.
  2. The Controller delegates the execution of “main” operation to the Model.
  3. The Model sends the results back to the Controller.
  4. The Controller formats the data and sends them to the View.
  5. The View takes the data, renders the HTML page, and sends it to the browser that requested it.

Build your first application

Starting the developing of an ASP.NET MVC application is easy. From Visual Studio just use the “File > New Project” menu

command, and select the ASP.NET MVC Project template (as shown in the following figure).

MVCProject_template

Type in the name of the project and press the “OK” button. It will ask you whether you want to create a test project (I suggest choosing Yes), then it will automatically create a stub ASP.NET MVC Web site with the correct folder structure that you can later customize for your needs.

folder_structure

As you can see, the components of the applications are wellseparated in different folders.

Folder Name Contains
/Content Static contents for your site, like CSS and images
/Controllers All the Controllers of the application, one per file
/Models The classes that encapsulate the interaction with the Model
/Scripts The JavaScript files used by your application (by default it contains jQuery
/Views All the views of the application, in sub-folders that are related one to one with the controllers

The Fundame ntals of ASP.NET MVC

One of the main design principles of ASP.NET MVC is “convention over configuration”, which allows components to fit nicely together based on their naming conventions and location inside the project structure.

The following diagram shows how all the pieces of an ASP.NET MVC application fit together based on their naming conventions:

MVCnaming

Routing

The routing engine is not part of the ASP.NET MVC framework, but is a general component introduced with .NET 3.5 SP1. It is the component that is first hit by a request coming from the browser. Its purpose is to route all incoming requests to the correct handler and to extrapolate from the URL a set of data that will be used by the handler (which, in the case of an ASP.NET MVC Web application, is always the MvcHandler) to respond to the request.

routing_engine

To accomplish its task, the routing engine must be configured with rules that tell it how to parse the URL and how to get data out of it. This configuration is specified inside the RegisterRoutes method of the Global.asax file, which is in the root of the ASP.NET MVC Web application.


public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
“Default”, //Route Name
“{controller}/{action}/{id}”, //Route Formats
new { controller = “Home”, action = “Index”, id = “” } //Defaults
);
}	

The snippet above shows the default mapping rule for each ASP.NET MVC application: every URL is mapped to this route, and the first 3 parts are used to create the data dictionary sent to the handler. The last parameter contains the default values that must be used if some of the URL tokens cannot be populated. This is required because, based on the default convention, the data dictionary sent to the MvcHandler must always contain the controller and the action keys.

Examples of other possible route rules:

URL Rule Data Dictionary
/Posts/Show/5

Format: “{controller}/
{action}/{id}”
Default: new { controller
= “Home”, action = “Index”,
id = “” }

Controller = Posts Action = Show Id = 5
/archive/2009-10-02/MyPost

Format: /archive/{date}/{title}
Default: { controller = “Posts”, action
= “show”}


Controller = Posts
Action = Show
Date = 2009-10-02
Title = My post

Model

ASP.NET MVC, unlike other MVC-based frameworks like Ruby on Rails (RoR), doesn’t enforce a convention for the Model. So in this framework the Model is just the name of the folder where you are supposed to place all the classes and objects used to interact with the Business Logic and the Data Access Layer. It can be whatever you prefer it to be: proxies for Web services, ADO.NET Entity Framework, NHibernate, or anything that returns the data you have to render through the views.

Controller

The controller is the first component of the MVC pattern that comes into action. A controller is simply a class that inherits from the Controller base class whose name is the name of a controller and ends with “Controller,” and is located in the Controllers folder of the application folder structure. Using that naming convention, the framework automatically calls the specified controller based on the parameter extrapolated by the URL.


namespace MyMvcApp.Controllers
{
	public class PageController : Controller
	{
	   //Controller contents.
	}
}	

The real work, however, is not done by the class itself, but by the method that lives inside it. These are called Action Methods.

Action Method

An action method is nothing but a public method inside a Controller class. It usually returns a result of type ActionResult and accepts an arbitrary number of parameters that contain the data retrieved from the HTTP request. Here is what an action method looks like:


public ActionResult Show(int id)
{
	//Do stuff
	ViewData[“myKey”]=myValue;
	return View();
}	

The ViewData is a hash-table that is used to store the variables that need to be rendered by the view: this object is automatically passed to the view through the ActionResult object that is returned by the action. Alternatively, you can create your own view model, and supply it to the view.

public ActionResult Show(int id)

{
  //Do stuff
  return View(myValue);
}

This second approach is better because it allows you to work with strongly-typed classes instead of hash-tables indexed with string values. This brings compile-time error checking and Intellisense.

Once you have populated the ViewData or your own custom view model with the data needed, you have to instruct the framework on how to send the response back to the client. This is done with the return value of the action, which is an object that is a subclass of ActionResult. There are various types of ActionResult, each with its specific way to return it from the action.

ActionResult Type Method Purpose
ViewResult View() Renders a view whose path is inferred by the current controller and action: /View/controllerName/ ActionName.aspx
ViewResult View(viewName)

Renders a view whose name is
specified by the parameter:
/View/controllerName/
viewName.aspx

ViewResult View(model) Renders the view using the default path, also passing a custom View Model that contains the data that needs to be rendered by the view.
PartialViewResult PartialView() Same as View, but doesn’t return a complete HTML page, only a portion of it. Looks for the file at following the path: /View/controllerName/ ActionName.ascx
PartialViewResult PartialView(viewName) Renders a partial view whose name is specified by the parameter: /View/controllerName/ viewName.ascx
PartialViewResult PartialView(model) Renders a partial view using the default path, also passing a custom View Model that contains the data that needs to be rendered by the partial view.
RedirectResult Redirect(url) Redirects the client to the URL specified.
RedirectToRouteResult RedirectToAction(actionName) Redirects the client to the action specified. Optionally you can specify also the controller name and an additional list of parameters.
RedirectToRouteResult RedirectToR Redirects the client to the route specified. Optionally you can specify an additional list of parameters.
ContentResult Content(content) Sends to the content specified directly to the client. Optionally you can specify the content type and encoding.
JsonResult Json(data) Serializes the data supplied in Json format and sends the Json string to the client.
FileResult File(filename,contenttype) Sends the specified file directly to the client. Optionally you can provide a stream or a byte array instead of a physical path.
JavaScriptResult JavaScript(javascript) Sends the script provided as external JavaScript file.
EmptyResult new EmptyResult() Doesn’t do anything: use this in case you handle the result directly inside the action (not recommended).

Model Binder

Using the ActionResults and the ViewData object (or your custom view model), you can pass data from the Action to the view. But how can you pass data from the view (or from the URL) to the Action? This is done through the ModelBinder. It is a component that retrieves values from the request (URL parameters, query string parameters, and form fields) and converts them to action method parameters.

As everything in ASP.NET MVC, it’s driven by conventions: if the action takes an input parameter named Title, the default Model Binder will look for a variable named Title in the URL parameters, in the query string, and among the values supplied as form fields.

model_binder

But the Model Binder works not only with simple values (string and numbers), but also with composite types, like your own objects (for example the ubiquitous User object). In this scenario, when the Model Binder sees that an object is composed by other sub-objects, it looks for variables whose name matches the name of the properties of the custom type. Here it’s worth taking a look at a diagram to make things clear:

model_binder_diagram

View

The next and last component is the view. When using the default ViewEngine (which is the WebFormViewEngine) a view is just an aspx file without code-behind and with a different base class.

Views that are going to render data passed only through the ViewData dictionary have to start with the following Page directive:


<%@ Page Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master”
Inherits=”System.Web.Mvc.ViewPage” %>


If the view is also going to render the data that has been passed via the custom view model, the Page directive is a bit different, and it also specifies the type of the view model:


<%@ Page Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master”
Inherits=”System.Web.Mvc.ViewPage<PageViewModel>” %>

You might have noticed that, as with all normal aspx files, you can include a view inside a master page. But unlike traditional Web forms, you cannot use user controls to write your HTML markup: you have to write everything manually. However, this is not entirely true: the framework comes with a set of helper methods to assist with the process of writing HTML markup. You’ll see more in the next section.

Hot Tip

Another thing you have to handle by yourself is the state of the application: there is no ViewState and no Postback.

HTML helper

You probably don’t want to go back writing the HTML manually, and neither does Microsoft want you to do it. Not only to help you write HTML markup, but also to help you easily bind the data passed from the controller to the view, the ASP.NET MVC Framework comes with a set of helper methods collectively called HtmlHelpers. They are all methods attached to the Html property of the ViewPage. For example, if you want to write the HTML markup for a textbox you just need to write:


<%= Html.Textbox(“propertyName”)%>

And this renders an HTML input text tag, and uses the value of the specified property as the value of the textbox. When looking for the value to write in the textbox, the helper takes into account both the possibilities for sending data to a view: it first looks inside the ViewData hash-table for a key with the name specified, and then looks inside the custom view model, for a property with the given name. This way you don’t have to bother assigning values to input fields, and this can be a big productivity boost, especially if you have big views with many fields.

Let’s see the HtmlHelpers that you can use in your views:

Helper Purpose

Html.ActionLink(text,
actionName, …)

Renders a HTML link with the text specified, pointing to the URL that represents the action and the other optional parameters specified (controller and parameters). If no optional parameters are specified, the link will point to the specified action in the current controller.

Html.RouteLink(text,
routeValues, …)

Renders a HTML link as the method ActionLink, but now using the route values, and optionally the route name, as input.
Html.BeginForm(actionName,…) Renders the beginning HTML form tag, setting as action of the form the URL of the action specified. The URL creation works exactly the same as the ActionLink method.
Html.EndForm() Renders the form closing tag.
Html.Textbox(name) Renders a form input text box, populating it with the value retrieved from the ViewData or custom view model object. Optionally you can specify a different value for the field, or specify additional HTML attributes.
Html.TextArea(name, rows, cols, …) Same as Textbox, but renders a textarea, of the specified row and column size.
Html.Checkbox(name) Renders a checkbox.
Html.RadioButton(name, value) Renders a radio button with the given name, the given value and optionally specifying the checked state.
Html.Hidden(name) Renders a form input field of type hidden.

Html.DropDownList(name,
selectList,…)

Renders a select HTML element, reading the options from the selectList variable, which is a list of name-value pairs.

Html.ListBox(name,
selectList,…)

Same as the DropDownList method, but enables the ability to select multiple options.

Html.
ValidationMessage(modelName, …)

Displays a validation message if the specified field contains an error (handled via the ModelState).
Html.ValidationSummary(…) Displays the summary with all the validation messages of the view.

Html.
RenderPartial(partialViewName)

Renders on the view the contents of the specified partial view.

As alternative to writing Html.BeginForm and Html.CloseForm methods, you can write an HTML form by including all its elements inside a using block:


<% using(Html.BeginForm(“Save”)) { %>
<!—all form elements here -->
<% } %>

To give you a better idea of how a view that includes an editing form looks like, here is a sample of a complete view for editing an address book element:


<%@ Page Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master”
Inherits=”System.Web.Mvc.ViewPage<EditContactViewModel>” %>
<% using(Html.BeginForm(“Save”)) { %>
Name: <%= Html.Textbox(“Name”) %> <br/>
Surname: <%= Html.Textbox(“Surname”) %> <br/>
Email: <%= Html.Textbox(“Email”) %> <br/>
Note: <%= Html.TextArea(“Notes”, 80, 7, null) %> <br/>
Private <%= Html.Checkbox(“IsPrivate”) %><<br/>
<input type=”submit” value=”Save”>
<% } %>

T4 Templates

But there is more: bundled with Visual Studio there is a template engine (made T4 as in Text Template Transformation Toolkit) that helps automatically generate the HTML of your views based on the ViewModel that you want to pass to the view.

The “Add View” dialog allows you to choose with which template and based on which class you want the views to be generated

Template Name Purpose
Create Generates a form to create a new instance of the item you selected
Details Generates a view that shows all the properties of the item you selected
Edit Generates a form to edit a instance of the item you selected
Empty Generates an empty view, only with the declaration of the class it’s based on
List Generates a view with a list of the items you selected

Add View dialog

What these templates do is mainly iterating over all the properties of the ViewModel class and generating the same code you would have probably written yourself, using the HtmlHelper methods for the input fields and the validation messages.

For example, if you have a view model class with two properties, Title and Description, and you choose the Edit template, the resulting view will be:


<%@ Page Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/Site.
Master”
Inherits=”System.Web.Mvc.ViewPage<IssueTracking.Models.Issue>” %>
<asp:Content ID=”Content1” ContentPlaceHolderID=”TitleContent”
runat=”server”>
	Edit
</asp:Content>


<asp:Content ID=”Content2” ContentPlaceHolderID=”MainContent”
runat=”server”>
  <h2>Edit</h2>
  <%= Html.ValidationSummary(“Edit was unsuccessful. Please correct
the errors and try again.”) %>
  <% using (Html.BeginForm()) {%>
    <fieldset>
       <legend>Fields<</legend>
       <p>
		<label for=”Title”>Title:</label>
		   	<%= Html.TextBox(“Title”, Model.Title) %>
		    <%= Html.ValidationMessage(“Title”, “*”) %>
	   </p>
	   <p>
			<label for=”Description”>Description:</label>
			<%= Html.TextArea(“Description”,
			    Model.Description,7,50,null)%>
            <%= Html.ValidationMessage(“Description”, “*”) %>
	   </p>
	    <p>
            <input type=”submit” value=”Save” />
       </p>
   </fieldset>
<% } %>
  <div>
       <%=Html.ActionLink(“Back to List”, “Index”) %>
  </div>
</asp:Content>

Ajax

The last part of ASP.NET MVC that is important to understand is AJAX. But it’s also one of the easiest aspects of the framework.

First, you have to include the script references at the top of the page where you want to enable AJAX (or in a master page if you want to enable itfor the whole site):


<script src=”/Scripts/MicrosoftAjax.js” type=”text/javascript”><script>
<script src=”/Scripts/MicrosoftMvcAjax.js” type=”text/javascript”></script>

And then you can use the only 2 methods available in the AjaxHelper: ActionLink and BeginForm.

They do the exact same thing as their HtmlHelper counterpart, just asynchronously and without reloading the page. To make the AJAX features possible, a new parameter is added to configure how the request and the result should be handled. It’s called AjaxOptions and is a class with the following properties:

Parameter Name Purpose
UpdateTargetId The id of the html element that will be updated
InsertionMode Where the new content will be inserted:
  • Replace: new content will replace old one
  • InsertAfter: new content will be placed after the current one
  • InsertBefore: new content will be placed before
Confirm The question that will be asked to the user to confirm their will to proceed
OnBegin Generates an empty view, only with the declaration of the class it’s based on
OnSuccess Generates a view with a list of the items you selected
OnFailure Name of the JavaScript function to be called before the request starts
OnComplete Name of the JavaScript function to be called when the request is complete, either with a success or a failure
Url The URL to sent the request to, if you want to override the URL calculated via the usual actionName and controllerName parameters
LoadingElementId The id of the HTML element that will be made visible during the execution of the request

For example, here is a short snippet of code that shows how to update a list of items using the AJAX flavor of the BeginForm method:


<ul id=”types”>
<% foreach (var item in Model) { %>
  <li><%= item.Name %></li>
<% } %>
</ul>
<% using(Ajax.BeginForm(“Add”,”IssueTypes”,new AjaxOptions() {
    InsertionMode = InsertionMode.InsertAfter,
    UpdateTargetId = “types”,
    OnSuccess = “myJsFunc”
  })) { %>
Type Name: <%= Html.TextBox(“Name”) %>
<input type=”submit” value=”Add type” />
<% } %>

The AJAX call will be sent to the Add action inside the IssueType controller. Once the request is successful, the result sent by the controller will be added after all the list items that are inside the types element. And then the myJsFunc will be executed.

But what the ASP.MVC library does is just enabling these two methods: if you want more complex interactions you have to use either the AJAX in ASP.NET library or you can use jQuery, which ships as part of the ASP.NET MVC library.

If you want to use the AJAX in ASP.NET library, you don’t have to do anything because you already referenced it in order to use the BeginForm method, but if you want to use jQuery, you have to reference it as well.


<script src=”/Scripts/jquery-1.3.2.js” type=”text/javascript”></script>

One benefit of having the jQuery library as part of the ASP.NET MVC project template is that you gain full Intellisense support. But there is an extra step to enable it: you have to reference the jQuery script both with the absolute URL (as above) needed by the application and with a relative URL, which is needed by the Intellisense resolution engine. So, at the end, if you want to use jQuery and enable Intellisense on it, you have to add the following snippet:


<script src=”/Scripts/jquery-1.3.2.js” type=”text/javascript”>
</script>
<% if(false> { %>
<script src=”../../Scripts/jquery-1.3.2.js” type=”text javascript”>
</script>
<% } %>

About The Author

Photo of Simone Chiaretta

Simone Chiaretta

Simone Chiaretta is a software architect and developer who enjoys sharing his development experience and more than 10 years' worth of knowledge on Web development with ASP.NET and other Web technologies. He is currently working as a senior solution developer for Avanade, an international consulting company. He is an ASPInsider Microsoft MVP in ASP.NET, a core member of Subtext, a popular Open Source blogging platform, an active member of the Italian .NET User Group, co-founder of the Italian ALT.NET user group and a frequent speaker for community events throughout Italy.

Photo of Simone Chiaretta

Keyvan Nayyeri

Keyvan Nayyeri is a software architect and developer who has a bachelor of science degree in applied mathematics. He was born in Kermanshah, Kurdistan, in 1984. Keyvan's main focus is on Microsoft development technologies and their related technologies. Keyvan has a serious passion for community activities and open source software. He is also a team leader and developer of some prominent .NET Open Source projects, where he tries to learn many things through writing code for special purposes. Keyvan also has received a number of awards and recognition from Microsoft, its partners, and online communities. Some major highlights include Microsoft VSX Insider and Telligent Community Server MVP.

Recommended Book

ASP.NET-MVC1.0

If you have a background in .NET and ASP.NET and are seeking to learn ASP.NET MVC, then this is the book for you. Relying heavily on MVC concepts, ASP.NET MVC principles, and code to demonstrate the main content, this valuable resource walks you through the necessary components to solve real-world problems.


Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.

Liferay Essentials

A Definitive Guide for Enterprise Portal Development

By James Falkner

11,762 Downloads · Refcard 126 of 151 (see them all)

Download
FREE PDF


The Essential Liferay Cheat Sheet

Liferay, a free and open source enterprise portal written in Java. More than just a portal, Liferay in its eleventh year of development. It is a platform for creating effective business applications and solutions while portals (and portlets) remain the only reasonable way to offer multiple applications in a single UI. It offers a robust feature set, impressive scalability, time-saving development tools, support for over 30 languages, and a flexible architecture that is open source developed and enterprise refined. Contents for this card include web content management, workflow, administration, hot tips and more.
HTML Preview
Liferay Essentials A Definitive Guide for Enterprise Portal Development

Liferay Essentials: A Definitive Guide for Enterprise Portal Development

By James Falkner

INTRODUCTION

Liferay Portal is a free and open-source enterprise portal written in Java and distributed under the GNU LGPL. Now in its eleventh year of development, the award-winning product is one of the most widely deployed portal technologies on the market, with an estimated 250,000 deployments worldwide. More than a portal, Liferay is a platform for creating effective business applications and solutions. It offers a robust feature set, impressive scalability, time-saving development tools, support for over 30 languages, and a flexible, scalable architecture that is open-source developed and enterprise refined.

About this Refcard

This Refcard will help both novices and professionals quickly navigate some of Liferay’s most popular features and hidden gems. It will cover topics such as installation, configuration, administration, and development features.

Getting Set up

Liferay Portal Community Edition is freely downloadable from http://liferay.com. Click the Downloads link at the top of the page and you will be presented with multiple download options:

Bundles are archives that combine Liferay Portal with popular application servers such as Tomcat, GlassFish, and others.

Standalone (WAR) distributables contain Liferay Portal alone and are suitable for installation into an existing application server environment.

All bundles and WAR distributables are cross-platform and should run on any modern flavor of Windows, Linux, Mac OS X, or other Unix-based operating systems.

Bundle Directory Structure

liferay-portal-<version> This top-level folder is known as the Liferay Home directory.

Data: This folder is used to store the embedded HSQL database that the bundles use, as well as the configuration and data for the Jackrabbit JSR-170 content repository and the Lucene search index.

LiferayPortal

Deploy: Plugins that you wish to deploy to Liferay can be copied into this folder. It is also used by Liferay’s graphical plugin installer utility, which is available from the Control Panel.

License: This folder contains both Liferay’s license and a file that describes the licenses for many of the other open-source projects that are used internally by Liferay.

[Application Server]: There will also be an application server folder that is different depending on which bundle you have downloaded. This folder contains the application server in which Liferay has been installed.

Starting Liferay

In most cases, installing a bundle is as easy as uncompressing the archive and then starting the application server.

For example, Tomcat is started with:


$ ${LIFERAY_HOME}/tomcat-6.0.26/bin/startup.sh
$ tail –f ${LIFERAY_HOME}/tomcat-6.0.26/logs/catalina.out

Other bundles are started in a similar fashion.

Once started, your Web browser should automatically be launched and directed to http://localhost:8080, which should display the default Liferay website, as shown here.

Liferay Basics

Liferay is a portal server. This means that it is designed to be a single environment where all of the required applications (represented by individual portlets) can run, and these applications are integrated together in a consistent and systematic way.

Portal Architecture

In the illustration below, each arrow may be read using the words “can be a member of.” It is important to note that the diagram illustrates only users and their collections. Permissions ` do not flow through all of these collections; permissions can be assigned to roles only.

LiferayPortal

The following concepts are used throughout Liferay:

  • Portals are accessed by Users.
  • Users can be collected into User Groups.
  • Users can belong to Organizations and join/leave Communities.
  • Roles are collections of permissions on portal objects that can be assigned to Users.
  • Organizations can be grouped into hierarchies, such as Home Office  Regional Office  Satellite Office. Communities are not hierarchical.
  • Users, Groups, and Organizations can belong to Communities that have a common interest.
  • Within Organizations and Communities, users can belong to Teams, which are groupings of users for specific functions within a community or organization.
  • Users, Organizations and Communities have two separate collections of Pages called Public and Private Pages. Each page can have as many applications (portlets) as desired. The page administrator can lay out these applications into zones defined by a default or customized layout template.

WEB CONTENT MANAGEMENT

Liferay’s Web Content Management (WCM) is a system which allows non-technical users to publish content to the Web without having advanced knowledge of Web technology or programming of any sort. Liferay Content Management System (CMS) empowers you to publish your content with a simple point-andclick interface, and it helps you to keep your site fresh.

You can use WCM to author both structured and unstructured content. Unstructured content is authored using an HTML-based WYSIWYG editor. Structured content is authored and displayed by combining Web Content Structures, Web Content Templates, and Web Contents. Structures and Templates are defined individually using a text editor or through the Liferay WCM UI.

Accessing Structure Elements

The following table shows how to access structure data from your Web Content Template code (when using Velocity templates; other template languages such as FreeMarker, XSL, or CSS have similar constructs). The variable name defined in the structure are denoted in bold and will be different depending on the name assigned in the structure.

Element Type Velocity Template Accessors
Text Field $tf.name, $tf.data, $tf.type
Text Box $textbox.data
Text Area (HTML) $textarea.data
Checkbox $checkbox.data
Selectbox $selectbox.data
Multi-Selection List #foreach($selection in $mylist.options)
$selection
#end
Image Gallery <img src=”/image/image_gallery?img_id=$img.getData()”/>
Link to Page $linkToPage.url
Repeatable $el.siblings
Hierarchy #foreach($child in $el.children)
$child.data
#end
Reserved Variables $reserved-article-[id,version,title,create-date,modifieddate,display-date,author-id,author-name,author-emailaddress,author-comments,author-organization,authorlocation,author-job-title].data

Template and Theme Variables

The following table lists the most common built-in variables accessible from Velocity Template code (when using Velocity templates; other template languages such as FreeMarker, CSS, or XSL have similar constructs). For example, $layout.getChildren(). Items marked with an asterisk (*) are only available from Liferay Theme files.

Variable Name Description
request HTTPServletRequest object
company The current company object. This represents the portal instance on which the user is currently navigating.
companyId The current company ID.
groupId ID of the group in which this web content is published.
locale The current user's locale, as defined by Java.
randomNamespace A randomized string. It is very useful for creating IDs that are guaranteed to be unique.
browserSniffer Dynamic browser capabilities. e.g.$browserSniffer.isMobile()
portal Current portal instance
portletURLFactory Creates portlet URLs (action URLs, etc)
stringUtil Useful string utilities
portletConfig* Standard PortletConfig object describing information from the portal.xml file.
renderRequest* Standard Portlet RenderRequest object
renderResponse* Standard Portlet RenderResponse object
themeDisplay* Contains many useful items, such as the logged in user, the layout,logo information, paths, and much more.
user* The User object representing the current user.
layoutSet* The set of pages to which the user has currently navigated. Generally, communities and organizations have two: a public set and a private set.
scopeGroupId* groupId that is used to identify the scope where the data of the current portlet is stored and retrieved. The scope can represent a community, organization, user, the global scope, or a scope tied to a specific page.
timeZone* The current user's time zone, as defined by Java.
viewMode e.g. “print” when clicked print icon
fullTemplatesPath* Path to all templates used.
pageTitle* Title of the page
serviceLocator Access to other Liferay services. Note by default this variable is disabled, must be enabled via portal-ext.properties
prefsPropsUtil Access to portal settings that were set from the Control Panel or through the portal.properties configuration file.
permissionChecker An object which can determine given a particular resource whether or not the current user has a particular permission for that resource.
[css|images|javascrip
t|templates]_folder*
Full path to various theme files

Hot Tip

A web Content Template that is set as Cacheable will return a cached result when accessing the variables (potentially returning stale or sensitive data). To ensure you get an uncached result, make sure that you uncheck the Cacheable option for your Web Content Template.

WORKFLOW

A Liferay Workflow is a predetermined sequence of connected steps. In Liferay, workflow is designed to manage the creation, modification, and publication of all supported web content types (including Web Content, Blogs, Wikis, Message Boards, Documents, and other user-generated content). Liferay ships with a default workflow engine called Kaleo. It can generate and reference roles scoped for Organizations, Communities, and for the entire Portal. This engine is deeply integrated with Liferay, but can be replaced with an external engine, such as jBPM.

Kaleo Workflow Definitions

Liferay comes with a default Kaleo workflow definition called “Single Approver” that means that a single approval is needed before content is published. You can create custom workflow definitions by using the APIs and workflow definition format provided. An example skeleton of a simple workflow is shown below:


<workflow-definition>
	<name>MyName</name>
	<version>1</version>
	<state>
	</state>
	<state>
	</state>
	<task>
	</task>
	<task>
	</task>
</workflow-definition>

Assets, States, Transitions, and Tasks

The key parts of the workflow definition are the asset, states, transitions, and tasks. The asset is whatever piece of content is being reviewed and approved in the workflow. States represent stages of the workflow, such as “created”, “rejected”, or “approved”. Transitions occur between states, and indicate what the next state should be. Tasks are steps in the workflow that require user action.

Example State

<state>
  <name>MyState</name>
  <initial>true</initial>
  <actions>
   <action>
	 <name>SomeAction</name>
	 <execution-type>onEntry</execution-type>
	 <script>
	    <![CDATA[
     // some javascript code here
        ]]>
	</script>
	<script-language>javascript</script-language>
	<priority>7</priority>
   </action>
  </actions>
  <transitions>
    <transition>
	 <name>Task1</name>
	 <target>task1</target>
	 <default>true</default>
    </transition>
  </transitions>
</state>

Notable Elements Options
<actions> Defines actions to be taken upon entering state
<transitions> Defines possible transitions out of this state
<script-language> groovy, javascript, python, ruby
<priority> Integer, controls execution order of actions
<execution-type> onEntry, onAssignment, onExit
<template-language> text, velocity, freemarker
<notification-type> email, im, private-message
Example Task


  <task>
	<name>MyTask</name>
	<due-date-duration>12</due-date-duration>
	<due-date-scale>day</due-date-scale>
	<actions>
	  <notification>
		<name>A Notification</name>
		<execution-type>onAssignment</execution-type>
		<template>You have a new task</template>
		<template-language>text</template-language>
		<notification-type>email</notification-type>
	  </notification>
	</actions>
	<assignments>
	  <roles>
		<role>
			<role-type>community</role-type>
	    	<name>Community Administrator</name>
	    </role>
 	  </roles>
	</assignments>
	<transitions>
	  <transition>
		<name>Transition1</name>
		<target>state1</target>
		<default>true</default>
      </transition>
	   <transition>
		  <name>Transition2</name>
		  <target>state2</target>
		  <default>false</default>
	   </transition>
      </transitions>
 </task>

Notable Elements Options
<due-date-duration> Defines when the task is due
<ue-date-scale> second, minute, hour, day, week, month, year
<roles> Users who have this role can be assigned this task
<role-type> regular, community, organization

LIFERAY ADMINISTRATION

Portal Properties

Liferay uses the concept of overriding the defaults in a separate file, rather than going in and customizing the default configuration file. The default configuration file is called portal. properties, and it resides inside of the portal-impl.jar file. This .jar file is located in Liferay Portal’s WEB-INF/lib folder. If you have a copy of the Liferay source code, this file can be found in portal-impl/src. The file which is used to override the configuration is portal-ext.properties. This file can be created in your Liferay Home folder or anywhere in the application server’s classpath.

Database Setup

Out of the box, Liferay bundles are configured to use HSQLDB, which should only be used for development or demo purposes. You cannot use this database in production.

For production use, Liferay supports the following databases: MySQL, Microsoft SQL Server, Oracle Database, IBM DB2, PostgresSQL, and Sybase. Liferay can also connect to Apache Derby, Firebird, Informix, Ingres, or SAP DB. To use these databases, the database and user with appropriate access must be created, and the appropriate JDBC driver must be available in your app server. Consult your database documentation for details on syntax and how to create databases and users.

To use a particular database, you must set the following four properties in your portal-ext.properties.

MySQL Example:

1. jdbc.default.driverClassName=com.mysql.jdbc.Driver
2. jdbc.default.url=jdbc:mysql://localhost/lportal?
			useUnicode=true&characterEncoding=UTF-
			8&useFastDateParsing=false
3. jdbc.default.username=
4. jdbc.default.password=

Oracle Example:

jdbc.default.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.default.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.default.username=lportal
jdbc.default.password=lportal

It’s also possible to delegate this configuration to the application server through a DataSource by using the following property:


jdbc.default.jndi.name=NameOfDataSource

App Server Configuration

Liferay is supported on the following app servers or servlet containers: Geronimo, GlassFish, JBoss, Jetty, JOnAS, Oracle, Resin, Tomcat, WebLogic, and WebSphere. Consult your app server documentation for details on configuration. The following table lists common files that are involved in configuring your app server.

Tomcat 6.x Location
Global Libraries ${TOMCAT_DIR}/lib/ext
Portal Libraries ${TOMCAT_DIR}/webapps/ROOT/WEB-INF/lib
Primary Configuration ${TOMCAT_DIR}/conf/server.xml
Primary Log Files ${TOMCAT_DIR}/logs/catalina.out
GlassFish 3.x Location
Default Domain Directory ${GLASSFISH_DIR}/domains/domain1
Global Libraries ${GLASSFISH_DOMAIN_DIR}/lib
Portal Libraries ${GLASSFISH_DOMAIN_DIR}/applications/j2ee-modules/Liferay-portal/WEB-INF/lib
Primary Configuration ${GLASSFISH_DOMAIN_DIR}/config/domain.xml
Primary Log Files ${GLASSFISH_DOMAIN_DIR}/logs/server.log
JBoss 5.x Location
Default Instance Directory ${JBOSS_DIR}/server/default
Global Libraries ${JBOSS_INSTANCE_DIR}/lib
Portal Libraries ${JBOSS_INSTANCE_DIR}/deploy/ROOT.war/WEB-INF/lib
Primary Configuration ${JBOSS_INSTANCE_DIR}/conf/jboss-service.xml
Primary Log Files ${JBOSS_INSTANCE_DIR}/log/server.log ${JBOSS_INSTANCE_DIR}/log/boot.log

Troubleshooting and Debugging

The following items should be checked when troubleshooting a problem.

Item Notes
Log Files Log files for several app servers are listed above. These should be checked for warnings, errors, Java stack traces, etc.
Log Settings Liferay uses the Apache Log4j library to perform all of its logging operations. See below on how to configure log settings.
JMX Liferay provides out-of-the-box JMX MBeans, which allow introspection into the runtime, for example to identify and isolate problematic behavior such as poor cache performance or slow portlet rendering.
Debug To attach a Java debugger to Liferay, you must start the JVM with special properties. Some servers have done this for you. For example, to start Tomcat under a debugger, run “bin/catalina.sh jpda start”
Other servers may need the JVM properties added manually. A typical set of properties is:
-Xdebug
-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

Logging Configuration

Liferay uses Log4j for its logging operations. When debugging an issue, it is useful to be able to increase verbosity of certain areas of Liferay to diagnose an issue. There are two ways to do this:

Interactively

Interactively changing the log levels will only persist until the next system restart, when the log level settings will revert to their previous values. This is done through the Control Panel-> Server Administration -> Log Levels user interface.

Config File

To make a more permanent change, copy Liferay’s default METAINF/portal-log4j.xml file from the portal-impl.jar, rename to portal-log4j-ext.xml, make any edits, and place the file somewhere along the servers classpath. For example, if you were using Tomcat, one could create ${TOMCAT_DIR}/lib/META-INF/portal-log4j-ext.xml.

For example, to enable debug logging for Hibernate, add this to your portal-log4j-ext.xml file:


<category name=”org.hibernate”>
 	<priority value=”DEBUG” />
</category>

Hot Tip

JBoss includes its own Log4j configuration that may override Liferay’s configuration. The JBoss Log4j configuration file can be found in $JBOSS/server/default/ conf/log4j.xml. Read the JBoss documentation for details.

Portal Properties

Listed below are several properties and descriptions that can be used to configure Liferay. These settings belong in your portal-ext.properties file.

Property Name Description and Examples
liferay.home
Default: Depends on App Server
Specifies the root of Liferay’s working directory /configuration. Example: /var/lr-home
portal.ctx
Default: /
Specifies the path of the portal servlet context. If you change this, you must also change the setting in web.xml Example: /mysite
jdbc.default.jndi.name
Default: Not Set
Set the JNDI name to lookup the JDBC data source. If none is set, then Liferay will attempt to create the JDBC data source based on the properties prefixed with jdbc. default. Example: jdbc/LiferayPool
jdbc.default.driverClassName
jdbc.default.url
jdbc.default.username
jdbc.default.password
Defaults: settings for HSQL
Database configuration options for creating the Liferay Database connection pool
company.default.web.id
Default: liferay.com
Default Web ID. Omni administrators must belong to this company. Example: mycompany.com

DEVELOPING FOR LIFERAY

You can develop many things both for and in Liferay: portlets, hooks, themes, layout templates, services, and more.

Plugins SDK

The Plugins SDK is both a project generator and a location where your projects are stored. Download the Plugins SDK from liferay.com/downloads/liferay-portal/additional-files.

Do not forget to create a build.username.properties file (where username is your OS username). Set the app.server.dir property to point at an extracted Liferay/App Server bundle. For example, app.server.dir=${user.home}/lr-6.0.5.

Building projects in the Plugins SDK requires that you have Ant 1.7.0 or higher installed on your machine. Download the latest version of Ant from http://ant.apache.org/.

Creating and Deploying New “Hello World” Plugins

Use the “create” script for creating new portlet, theme, hook, layout, or Web plugins:


$ cd portlets; ./create.sh hello-world “Hello World Portlet”
$ ant deploy

Other ANT targets include: Clean: removes build artifacts. War: creates distributable .war file. Compile: compiles source code. build-service: invokes Liferay’s Service Builder to create and build service source code.

Anatomy of a Portlet Project

Several directories and files are created when you use the create.sh tool.

Folder Description
docroot This folder is the “root” of your application.
WEB-INF Standard WEB-INF folder for Web applications. Also contains Liferayspecific descriptors.
WEB-INF/src Portlet source code.
build.xml ANT build script controlling building and deploying your plugin.
liferay-display.xml Describes what category the portlet should appear under in the Liferay UI.
liferay-pluginpackage.
properties
Describes properties used by Liferay’s hot-deploy mechanism.
liferay-portlet.xml Describes Liferay-specific portlet enhancements (akin to portlet.xml for generic portlets). There are many settings here to customize your portlet.
portlet.xml Standard JSR-168 or JSR-286 portlet descriptor
web.xml Standard Web Application descriptor

Liferay Hooks

Hooks are the best way to extend or modify Liferay’s behavior. They allow you to override parts of core Liferay with custom implementations. You specify what you wish to hook into in your liferay-hook.xml file. Within this file, you can customize:

Portal Properties

<hook>
<portal-properties>my.custom.portal.propertie</portal-properties>
</hook>

Within custom properties files, add startup action:


application.startup.events=org.mypkg.MyStartupEventClass

Add Model Listener for Blogs:


value.object.listener.com.liferay.portlet.blogs.model.BlogsEntry=org.mypkg.
BlogEntryAction

Language Properties

<hook>
<language-properties>content/Language_fr.properties</language-properties>
</hook>

JSP File Override

Allows overriding of any JSP from the core of Liferay by using the same paths as Liferay uses within the specified directory. Use with care:


<hook>
<custom-jsp-dir>/META-INF/custom_jsp</custom-jsp-dir>
</hook>

Then create custom JSPs:


/META-INF/custom_jsps/html/portlet/blogs/view.jsp
/META-INF/custom_jsps/html/portlet/calendar/week.jsp

Services

By wrapping services it’s possible to extend any core Liferay service method to perform additional operations or even to replace the default operations.


<hook>
  <service>
	<service-type>
	  com.liferay.portal.service.UserLocalService
	</service-type>
	<service-impl>
	  com.liferay.test.hook.service.impl.MyUserLocalServiceImpl
	</service-impl>
  </service>
</hook>

Liferay Themes

Themes are plugins, and are therefore hot-deployable just like portlet plugins. You can use the Plugins to build your themes automatically so that they can be deployed to any Liferay instance. The Plugins SDK packages a theme into a .war file just like a portlet, and this .war file can then be hot-deployed to Liferay.

Anatomy of a Theme
Path within Theme Description
/css/base.css, custom.css, … Defines many aspects of Liferay’s UI. To override, create your own _diffs/css/custom.css within your theme source code
/images/ Static image resources references from CSS, JS, VM, etc.
/javascript/main.js Defines stub functions that fire at certain points of page loading when using theme. Override using custom main.js
/templates/ Various Velocity Macro Templates that are executed during page rendering
init-custom.vm Allows you to add your own custom Velocity variables
init.vm Sets many Velocity variables that correspond to Liferay Java objects. See the section on Web Content for common variables available from your custom theme code.
navigation.vm Implements the page navigation within the theme
portal_normal.vm The overall template for all pages the theme implements. This file includes the other files.
portal_pop_up.vm The overall template for any portlets which implement popup windows.
portlet.vm The template for portlet windows within the theme.

Service Builder

Service Builder is a source code generation tool built by Liferay to automate the creation of interfaces and classes for database persistence, local and remote services. This is useful when developing data-driven applications that make frequent calls to the underlying database.

service builder

Hot Tip

A “service” in Liferay is simply a class or set of classes designed to handle retrieving and storing data classes. A local service is used by code running in the local instance of Liferay, while a remote service can be accessed from anywhere over the internet or your local network. Remote services support SOAP, JSON, and Java RMI.
Sample Service

Services are defined by creating a service.xml file. Once defined, source code can be generated for the persistence and data access/transfer layers of your Data-driven app. An example:


<service-builder package-path=”com.sample.portlet.library”>
  <namespace>Library</namespace>
  <entity name=”Book” local-service=”true” remote-service=”true”>
	<!-- PK fields -->
	<column name=”bookId” type=”long” primary=”true” />
	<!-- Group instance -->
	<column name=”groupId” type=”long” />
	<!-- Audit fields -->
	<column name=”companyId” type=”long” />
	<column name=”userId” type=”long” />
	<column name=”userName” type=”String” />
	<column name=”createDate” type=”Date” />
	<column name=”modifiedDate” type=”Date” />
	<!-- Other fields -->
	<column name=”title” type=”String” />
  </entity>
</service-builder>

Generating the Code

$ ant build-service

JSP Variable Reference

To get access to Liferay contextual objects when writing a JSP:


<liferay-theme:defineObjects />

Then, the following variables are available to your JSP:

Variable Name Description
themeDisplay A runtime object which contains many useful items, such as the loggedin user, the layout, logo information, paths, and much more.
company The current company object. This represents the portal instance on which the user is currently navigating.
account The user's account object. This object maps to the Account table in the Liferay database.
user The User object representing the current user.
realUser When an administrator is impersonating a user, this variable tracks the administrator's user object.
contact The user's Contact object. This object maps to the Contacts table in the Liferay database.
layout The set of pages to which the user has currently navigated. Generally, communities and organizations have two: a public set and a private set.
plid A Portal Layout ID. This is a unique identifier for any page that exists in the portal, across all portal instances.
layoutTypePortlet This object can be used to programmatically add or remove portlets from a page.
scopeGroupId A unique scope identifier for custom scopes, such as the page scope that was introduced in Liferay Portal 5.2.
permissionChecker An object that can determine, given a particular resource, whether or not the current user has a particular permission for that resource.
locale The current user's locale, as defined by Java.
timeZone The current user's time zone, as defined by Java.
theme An object representing the current theme that is being rendered by the portal.
colorScheme An object representing the current color scheme in the theme that is being rendered by the portal.
portletDisplay An object that gives the programmer access to many attributes of the current portlet, including the portlet name, the portlet mode, the ID of the column on the layout in which it resides, and more

Social Tools and Activity Streams

Liferay’s portal, content, and collaboration frameworks are tied together using a rich suite of social features. For developers, plugging social software into Liferay can be achieved in many ways. For example, using the native Social Relationship API for managing relationships between users (via the com.liferay.portlet. social package), interacting with the Activity Stream (via the SocialActivity model), calculating and visualizing Social Equity participation and contribution values, or dropping OpenSocial gadgets onto a page and managing via Liferay’s Control Panel.

More Information

For up-to-date and in-depth information, please refer to the official documentation for Liferay at http://www.liferay.com/ documentation.

About The Authors

Photo of author James Falkner

James Falkner

James Falkner is an open source evangelist, community manager, and software developer working at Liferay, producers of the world’s leading open source enterprise portal. In addition to Liferay, James has been active in a number of other open source products and projects, including the GlassFish Enterprise portfolio, Community/Social Equity, OpenSolaris, OASIS standards, and more. James is a regular contributor and speaker at industry events such as JavaOne, JAX, and others.

Websites: http://www.liferay.com/web/james.falkner

Email: james.falkner@liferay.com

Blog: http://www.liferay.com/web/james.falkner/blog

Recommended Book

Liferay in action

Liferay in Action is a comprehensive and authoritative guide to building portals on the Liferay 6 platform. Fully supported and authorized by Liferay, this book guides you smoothly from your first exposure to Liferay through the crucial day-to-day tasks of building and maintaining an enterprise portal that works well within your existing IT infrastructure. The book starts with the basics: setting up a development environment and creating a working portal. Then, you’ll learn to build on that foundation with social features, tagging, ratings, and more. As the book progresses, you’ll explore the Portlet 2.0 API, and learn how to create your own portlet applications.


Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.

Open Source Media Framework

Building Simple Custom Video Players

By R Blank

7,235 Downloads · Refcard 121 of 151 (see them all)

Download
FREE PDF


The Essential Adobe OSMF Cheat Sheet

The Open Source Media Framework (OSMF) is an Adobe-led, open-source ActionScript 3 coding framework for loading, playing and displaying media. Just as Adobe created the Flex Framework to standardize and expedite the creation of applications on the Flash Platform, OSMF is a means to standardize media handling in your Flash Platform experiences. With video, audio, and image playback handled so differently in AS3, OSMF succeeds at creating a simplified, standard way to work with all media inside Flash. In this DZone Refcard you will learn about Strobe Media Playback, Flash Media, key events, streaming, composite elements, and more.
HTML Preview
Open Source Media Framework: Building Simple Custom Video Players

Open Source Media Framework: Building Simple Custom Video Players

By R Blank

ABOUT OSMF

The Open Source Media Framework (OSMF) is an Adobe-led, open-source ActionScript 3 coding framework for loading, playing and displaying media. The website is http://osmf.org.

Just as Adobe created the Flex Framework to standardize and expedite the creation of applications on the Flash Platform, OSMF is a means to standardize media handling in your Flash Platform experiences.

Why are the loading and playback of sounds, videos and images each handled so differently in AS3? Why is building a streaming video player so much more difficult than building a progressive video player? Why is controlling volume so non-intuitive?

With OSMF, all those annoying questions disappear, as we now have a simple, clean and standard way of working with all media inside of Flash.

Getting OSMF

OSMF is a framework—which means that you need to install the OSMF library if you wish to use it in your code.

Download the current version of OSMF (v1.5 at the time of authoring) from http://opensource.adobe.com/wiki/display/osmf/Downloads. The Source .zip from this page includes both the ActionScript source for OSMF, as well as the compiled SWC component for use in development. You may also download the ASDoc documentation for the OSMF classes at the same URL.

Installing OSMF

If you are using Flash Builder, add OSMF.swc to the libs folder in your project, or to your standard library paths. Please note that Flash Builder 4 ships with a version of OSMF.swc that you will likely want to remove prior to installing the new OSMF.swc into your library paths. To remove the default version of OSMF from your project, select ‘Project > Properties’ from the menu. Select ‘Flex Build Path’ from the menu on the left side of the dialog box, and then click on the the ‘Library path’ tab. Expand the tree branch for the version of the Flex Framework you are using, select the OSMF. swc and then click on ‘Remove’. Click ‘OK’.

If you are using Flash CS4 or Flash Professional CS5, then you will want to copy OSMF.swc to:


		On Windows: \Program Files\Adobe\Adobe Flash CS[#]\
Common\Configuration\ActionScript 3.0\libs
		On Mac: /Applications/Adobe Flash CS[#]/Common/
Configuration/ActionScript 3.0/libs

Testing OSMF Installation

Write these two lines of ActionScript and try to compile your project—if this code works, you have successfully installed OSMF:


import org.osmf.media.MediaPlayer;
var mediaPlayer : MediaPlayer = new MediaPlayer();

CAPABILITIES

Supported Media Formats

OSMF supports any type of media that can be loaded by Flash, including (streaming audio) mp3, AAC, Speex, and Nellymoser; (streaming video) FLV, F4V, MP4, MPEG-4: MP4, M4V, F4V, 3GPP; (audio) mp3; (video) FLV, F4V, MP4, MP4V-ES, M4V, 3GPP, 3GPP2, QuickTime; (images) PNG, GIF, or JPG; and SWF files.

Support for Standards

OSMF also comes packaged with support for media standards including Video Ad Serving Template (VAST), Media Abstract Sequencing Template (MAST), Media RSS (MRSS), Distribution Format Exchange Profile (DFXP), and Synchronized Multimedia Integration Language (SMIL).

Flash Player 10 or 10.1?

There are different versions of OSMF depending on whether you are publishing to Flash Player 10 or 10.1 (OSMF is unsupported in Flash Player 9 and earlier), and both are included in the standard OSMF download. Which do you want to use?

If you want to utilize HTTP Streaming, DRM, and Multicast, then you must use OSMF for FP 10.1—otherwise, the functionality of both versions is equivalent.

Plug-ins

OSMF includes a plug-in architecture, enabling you and other third party developers to create useful and reusable functionality for OSMF experiences. Due to space considerations, plug-ins are not covered in this Refcard. For more information on OSMF plug-ins, visit http://opensource.adobe.com/wiki/display/osmf/Plugins. For a list of available OSMF plug-ins (for example, to facilitate playing media from Akamai’s CDN, or to implement Omniture tracking), visit http://osmf.org/partner.php.

STROBE MEDIA PLAYBACK AND FLASH MEDIA PLAYBACK

OSMF is a coding framework and includes no GUI or graphical options at all—OSMF is just logic. There are no OSMF-based components in Flash Professional, or the Flex Framework. If you want a quick video player, or a sample OSMF video player to use as a starting point, you can use Strobe Media Playback (SMP) and Flash Media Playback (FMP).

SMP is an open-source Flash video player, built on OSMF, that includes a full GUI, with elements like a play button, a volume slider and a progress bar. You can use SMP to get a kick-start working with OSMF, and then customize and redeploy SMP for your own uses. For more information on, and to download SMP, visit http://osmf.org/strobe_mediaplayback.html.

FMP is a version of SMP hosted by Adobe. Simply visit the FMP Configurator at http://www.osmf.org/configurator/fmp/, enter the location of your video file, copy the embed code, and paste it into any web page and voila!—you have an OSMF player in seconds. For more information on FMP, visit http://www.adobe.com/products/flashmediaplayback/.

Both SMP and FMP are easily skinnable, and playback options are rapidly customized through FlashVar parameters.

THE BASIC OSMF PLAYER

At the heart of any OSMF experience are three classes: the MediaElement, the MediaPlayer, and the MediaContainer.

diagram1

MediaElement

The MediaElement is used to load media.

You generally would not use the MediaElement directly—there are several descendants of the MediaElement, including AudioElement (to load audio) and ImageElement (to load images). In this example, we will use the VideoElement (to load video). When creating a new VideoElement, you pass in a URLResource pointing to the video you wish to play, as in:


var videoElement = new VideoElement(new URLResource(“my.flv”));

MediaPlayer

The MediaPlayer is used to play media stored in
MediaElement instances.

The MediaPlayer has a media property; we use this to instruct the MediaPlayer which piece of media to playback. The MediaPlayer may be reused to play multiple pieces of content.


var mediaPlayer : MediaPlayer = new MediaPlayer();
mediaPlayer.media=videoElement;

MediaContainer

The MediaContainer is used to display media stored in
MediaElement instances.


var container : MediaContainer = new MediaContainer();

As the MediaContainer makes our media visible to humans, it must reside in the Display List to be seen.


addChild(container);

Finally, we add our MediaElement to our MediaContainer by calling the addMediaElement method:


container.addMediaElement(videoElement);

Imports

Even if you are accustomed to coding on the timeline in Flash Professional, you still must import OSMF classes for them to be used. You can always reference the OSMF documentation (which can be downloaded as a .zip from http://opensource.adobe.com/ wiki/display/osmf/Downloads) to determine the location of the classes you need to import. For this simple OSMF player, four imports are required.

Putting it all Together

These are the four imports and six lines of code in the basic OSMF video player:


import org.osmf.containers.MediaContainer;
import org.osmf.elements.VideoElement;
import org.osmf.media.MediaPlayer;
import org.osmf.media.URLResource;
var container : MediaContainer = new MediaContainer();
addChild(container);
var videoElement : VideoElement =new VideoElement(new URLResource(“my.flv”));
container.addMediaElement(videoElement);
var mediaPlayer : MediaPlayer = new MediaPlayer();
mediaPlayer.media=videoElement;

MORE USEFUL STUFF

Thus far, we’ve covered the basics—which are obviously an important place to start. But the real benefits of working with OSMF become clear once you start doing more—and you see how easy and standardized it all is.

Controlling Media Playback

We use the MediaPlayer to control media playback, with three methods. The default behavior of the MediaPlayer is to automatically play loaded media. To pause the media, we tell the MediaPlayer to pause:


mediaPlayer.pause( );

Similarly, to play (resume) our media:


mediaPlayer.play( );

And to jump around within our media file, we call the seek()method, passing in as a parameter the position within our media (in seconds) to which we wish to seek:


mediaPlayer.seek( 5 );

Customizing Layout

By default, a MediaContainer instance will display any visual media at its default size (100%) and position (0,0). We use the LayoutMetadata (org.osmf.layout.LayoutMetadata) class to customize the appearance of visual media, by creating a LayoutMetadata object, defining its properties, and then attaching it to our MediaElement.

First, we import the LayoutMetadata class.


import org.osmf.layout.LayoutMetadata ;

Then, we create a LayoutMetadata object:


var layout : LayoutMetadata = new LayoutMetadata();

Next, we customize the properties of our LayoutMetadata object. Four common properties to set are width, height, x and y:


layout.width=640;
layout.height=480;
layout.x=20;
layout.y=40;

Finally, we need to link our LayoutMetadata with the MediaElement instance it is intended to influence:


mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout);

Then, when our mediaElement is displayed in a MediaContainer, it will have our intentional, customized layout.

Key MediaPlayer Properties

The MediaPlayer includes several useful properties, which I’ve included here for reference:

MediaPlayer.duration

The duration (in seconds) of the playback length of the media loaded into the MediaElement playing back in this MediaPlayer instance (read-only).

MediaPlayer.volume

The volume (from 0 to 1) of the audio track of the MediaElement currently loaded into this MediaPlayer instance. By default, this is set to 1.

MediaPlayer.autoPlay

A boolean value determining whether or not to automatically begin playback on MediaElement instances loaded into this MediaPlayer instance. By default, this is true (playback begins immediately).

MediaPlayer.loop

A boolean value determining whether or not to automatically loop the playback of any MediaElement instances loaded into this MediaPlayer instance. When set to true, upon completion of playback, the MediaPlayer instance will rewind the loaded media and begin playback again. By default, this is set to false (media does not loop).

MediaPlayer.autoRewind

A boolean value determining whether or not this MediaPlayer instance will automatically rewind-and-pause when reaching the end of playback of any MediaElement instances loaded into it. By default this is set to true (will automatically return to the beginning of the media upon completion of playback). This property is ignored if the loop property is set to true.

Media Factories

Thus far, when we wanted to create a new MediaElement instance to load a video, we created a new VideoElement. But, of course, that code will now only work to load a video. Sometimes we want to write code more generically than that. What if we want to load an image instead? Or a sound file? Or some text? Do we have to re-write our code?

Actually, no. OSMF includes Media Factories—adorable, little assembly plants that can churn out any flavor of MediaElement instances. Just tell a Media Factory to load a file from a URL, and the factory will know exactly what type of MediaElement to create.

First, we import the DefaultMediaFactory class:


import org.osmf.media.DefaultMediaFactory ;

Then, we create a DefaultMediaFactory:


var mediaFactory : DefaultMediaFactory = new DefaultMediaFactory();

Finally, we tell the mediaFactory to produce a MediaElement from a URLResource, pointing to a file:


var mediaElement : MediaElement = mediaFactory.createMediaElement(new
URLResource(“my.flv”));

You will note that our MediaElement is strong-typed to MediaElement, instead of VideoElement—because we do not necessarily know at author time, what type of MediaElement will be required.

COMPOSITE ELEMENTS

CompositeElements are complex types of the MediaElement class. CompositeElements encapsulate multiple MediaElement instances in a single object.

As with MediaElements, we do not create CompositeElements directly, but instead work with descendants of the CompositeElement class.

SerialElements are used to play multiple MediaElements sequentially (one after the other). SerialElements can be used to emulate playlists.

ParallelElements are used to play multiple MediaElements concurrently (at the same time). ParallelElements can be used for any number of purposes, but could, for example, be used to combine playback of images and music (a dynamic slideshow, for example).

Creating CompositeElements

Determine whether you want a SerialElement or a ParallelElement. As you work with both types of CompositeElements identically in ActionScript, for the purposes of this example, we will work with a SerialElement to play two videos sequentially.

First, we import the SerialElement class:


import org.osmf.elements.SerialElement ;

Then, we create a new SerialElement:


var serialElement : SerialElement = new SerialElement ( ) ;

Populating CompositeElements

To populate our CompositeElement instance, we must first have our constituent MediaElement instances (in this case, we’ll define two VideoElement instances for sequential playback).


var mediaElement1 : MediaElement = mediaFactory.createMediaElement(new
URLResource(“some.flv”));
var mediaElement2 : MediaElement = mediaFactory.createMediaElement(new
URLResource(“other.flv”));

Once we have our MediaElement instances, we can add them to our CompositeElement, using the addChild() method (in a SerialElement, the MediaElement instances are played in the order in which they are added to the SerialElement):


serialElement.addChild ( mediaElement1 ) ;
serialElement.addChild ( mediaElement2 ) ;

Playing CompositeElements

Once our CompositeElement is populated, it is ready for playback. We play CompositeElements exactly the same way as simple MediaElement instances. We simply set the media property of our MediaPlayer to point to our CompositeElement:


mediaPlayer.media = serialElement;

Displaying CompositeElements

We add a CompositeElement instance to the display the same way we reveal a MediaElement—by attaching it to a MediaContainer:


mediaContainer.addMediaElement(serialElement);

We do NOT customize the layout of CompositeElement instances. Recall, CompositeElements can support multiple different pieces of media, of different types and characteristics, alone or in parallel; thus you will want to control the layout of each MediaElement individually anyway.

To customize the layout of media stored in CompositeElements, we work with LayoutMetadata objects, and apply them to the individual MediaElement instances (as we learned above).


layout : LayoutMetadata = new LayoutMetadata();
layout.width = 320;
layout.height = 240;
layout.x = 320;
layout.y = 240;
mediaElement1.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout);
mediaElement2.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout);

STREAMING

Streaming media, unlike progressively loaded media, is delivered (or ‘streamed’) in a series of packets that are continually delivered to the user during playback. For this reason, unlike progressively delivered media, media files that are streamed are never actually stored on viewer computers. Streaming is a very effective way to deliver large audio and video files and, in particular, streaming facilitates rapid and immediate seeking (with progressive media, you can only seek to those portions of the media that have already downloaded).

If you are interested in working more with streaming, and you are on a Windows or Linux machine, you can install a local developer version of Flash Media Server (which you may download from http://adobe.com/products/flashmediaserver/). If you are working on Mac, or you wish to develop your FMS work on a live server, you can lease FMS inexpensively from http://Influxis.com.

URL Formatting for Streaming

Before we get into the code for streaming, if you aren’t used to working with Flash Media Server, you may not be used to the rather awkward logic FMS requires with respect to streaming media file extensions.

If you are streaming an FLV, you strip the ‘.flv’ when calling the file, as in:


rtmp://myFMS.com/appDirectory/my

Basic RTMP Streaming

OSMF makes streaming incredibly easy. If you return to our ‘Basic OSMF Example, we can change the URL in this line of code:


var videoElement : VideoElement = new VideoElement(new URLResource(“my.flv”));

to (assuming you had a Flash Media Server setup at myFMS.com):


var videoElement : VideoElement = new VideoElement(new URLResource(“rtmp://myFMS.
com/appDirectory/my”));

And voila! Our player is now a streaming video player. Seriously, that’s it. But it gets better.

HTTP Streaming

The above is an example of RTMP streaming—or streaming with the real-time media protocol (used by Adobe’s Flash Media Server).

With Flash Player 10.1, you can now stream your media without an RTMP server, straight from your web server, utilizing HTTP Streaming (assuming your web server is configured to support it, which the majority are). It’s just what it sounds like—streaming video without Flash Media Server.

Can you guess how difficult the code is? Well, it’s the same code as we’ve already worked with, but instead of pointing to an FLV, F4V, MP4 or MP3, we point to an F4M file, or a Flash Media Manifest file, which is an XML file containing information about a Flash media asset. For example:


var videoElement : VideoElement = new VideoElement(new URLResource(“http://my.com/
my.f4m”));

For more information on F4M, reference the specification at http://opensource.adobe.com/wiki/display/osmf/Flash+Media+Manifest+File+Format+Specification.

Dynamic Streaming

Sometimes you want to prepare multiple versions of the same video, at different quality bitrates, so that viewers can enjoy the highest quality video possible, given their bandwidth. And, because a viewer’s bandwidth can change over time, you will want to query the active bandwidth repeatedly, and change to a higher or lower quality video if the viewer’s bandwidth has shifted.

This process is called Dynamic Streaming—delivering the highest quality video possible, at all times during the viewing experience, from a collection of videos encoded at different bitrates.

Though not quite as simple as basic streaming (after all, there’s more information we have to setup to get this working), implementing dynamic streaming with OSMF is remarkably easy.

DynamicStreamingResource

In all of the prior examples, we have utilized a URLResource to wrap the URL to our media file, when creating our VideoElement, as in:


var videoElement : VideoElement = new VideoElement(new URLResource(“my.flv”));

To implement dynamic streaming, we need to use a different class—the DynamicStreamingResource. When we create a DynamicStreamingResource, instead of pointing to a media file, we point to a Flash Media Server application directory. First, we import the DynamicStreamingResource class:


import org.osmf.net.DynamicStreamingResource ;

Then, we create a new DynamicStreamingResource:


var resource : DynamicStreamingResource = new DynamicStreamingResource ( “rtmp://
myFMS.com/myAppDir” ) ;

DynamicStreamingItem

Our resource now points to an entire directory, instead of a single file. Next, we must populate our DynamicStreamingResource with the information pointing to our actual video files.

To do so, we create a DynamicStreamingItem instance for each bitrate we intend to support. When creating a DynamicStreamingItem, we specify a filename (respecting FMS file extension rules, noted above), and a minimum supported bandwidth (in kilobits-per-second, or kbps) required to view this version of the video:


new DynamicStreamingItem ( “my_high” , 1500 )

In our code, we will store these DynamicStreamingItem instances in a vector (vectors are similar to arrays, but the values stored in the indices of a vector must conform to the same datatype—in this case, all values stored in our vector will be DynamicStreamingItem instances).

For our example, we will support three separate bitrates in our player: 400kbps (low), 800kbps (medium) and 1.5mbps (high). To start, of course, we will need to import the DynamicStreamingItem class:


import org.osmf.net.DynamicStreamingItem ;

Then, we will create our vector of DynamicStreamingItems (with a fixed length of 3, because we wish to support precisely three bitrates):


var vector : Vector. = new Vector. (
3 ) ;

Next, we will populate our vector with the three DynamicStreamingItem instances.


vector [ 0 ] = new DynamicStreamingItem ( “my_high” , 1500 ) ;
vector [ 1 ] = new DynamicStreamingItem ( “my_low” , 400 ) ;
vector [ 2 ] = new DynamicStreamingItem ( “my_medium” , 800 ) ;

Note that the ordering of DynamicStreamingItems in the vector is irrelevant.

Then, before we move on, we ensure that the streamItems property of our DynamicStreamingResource points to our vector:


resource.streamItems = vector ;

Bringing it all Together

There may be some new and long class names involved, but building a dynamic streaming player with OSMF is remarkably easy—the code is very brief (only 12 lines in this example) and very similar to the basic six lines of code we used to progressively play a single video:


var player : MediaPlayer = new MediaPlayer ( ) ;
var container : MediaContainer = new MediaContainer ( ) ;
addChild ( container ) ;
var resource : DynamicStreamingResource = new DynamicStreamingResource ( “rtmp://
myFMS.com/myAppDir” ) ;
vector [ 0 ] = new DynamicStreamingItem ( “my_high” , 1500 ) ;
vector [ 1 ] = new DynamicStreamingItem ( “my_low” , 400 ) ;
vector [ 2 ] = new DynamicStreamingItem ( “my_medium” , 800 ) ;
resource.streamItems = vector ;
videoElement = new VideoElement( resource ) ;
player.media = videoElement ;
container.addMediaElement ( videoElement ) ;

Subclipping

When you stream with an RTMP server, it is easy to play segments from entire videos—referred to as subclipping, or playing clips within clips.

We do this with the StreamingURLResource, which we can use instead of a regular URLResource. A StreamingURLResource points only to a specific portion of a streamed video, determined by in and out points (measured in seconds), set when you create the instance:


new StreamingURLResource( url, streamType , clipStartTime , clipEndTime );

There are many potential uses for subclipping, but an obvious one is the insertion of interstitial advertising. Let’s say we wish to stream a one-minute clip, and progressively deliver a video ad half way through (at 30 seconds). This will require two subclips (aka StreamingURLResources) and a regular URLResource (for the ad), connected by a SerialElement (so that they play sequentially, rather than concurrently).

To start, we import the StreamingURLResource class:


import org.osmf.net.StreamingURLResource ;

Then we can write the following code:


var serialElement : SerialElement = new SerialElement();
var resource1 = new StreamingURLResource( “rtmp://myFMS.com/app/vid1” , null, 0,
30 );
serialElement.addChild( new VideoElement( resource1 ) );
var resource2 : URLResource = new URLResource ( “myAd.flv” ) ;
serialElement.addChild( new VideoElement( resource2 ) );
var resource3 = new StreamingURLResource( “rtmp://myFMS.com/app/vid1”, null, 30,
60 );
serialElement.addChild( new VideoElement( resource3 ) );
var mediaPlayer : MediaPlayer = new MediaPlayer( serialElement );
var container : MediaContainer = new MediaContainer();
addChild( container );
container.addMediaElement( serialElement );

KEY EVENTS

A huge amount of OSMF just works. But when you start building larger and customized experiences (for example, a playlist-driven media player, with a control bar to manage playback), you will need to write a bit of your own code, to handle and respond to events coming from OSMF. For example, you may wish to know when to enable a custom pause button, or to toggle its state to look like a play button; or perhaps you wish to build a custom progress bar, and need to track the position of the media.

OSMF is a rich framework, there is a lot you can do with it, and there are many events within OSMF you can listen to and exploit. However, to get started building custom controls, there are a few events—all coming from the MediaPlayer—that are the most important to learn about and work with.

Remember: MediaPlayer instances can be re-used to playback multiple MediaElement and CompositeElement instances, of multiple types—so these events can be dispatched during playback of a MediaElement, or in between playback of different MediaElement instances.

MediaErrorEvent

The MediaErrorEvent (org.osmf.events.MediaErrorEvent) is dispatched on a MediaElement when there is an error loading the specified media (such as if the specified video file does not exist). The MediaErrorEvent can also be heard on the MediaPlayer to which the MediaElement is associated—so you may listen for this event on either type of object.

The code to listen for, and trace out the details of, a MediaErrorEvent is:


mediaPlayer.addEventListener ( MediaErrorEvent.MEDIA_ERROR , _onMediaError ) ;
function _onMediaError ( evt : MediaErrorEvent ) : void
{
		trace ( “_onMediaError () , evt.error : “ + evt.error ) ;
}

TimeEvent

The TimeEvent (org.osmf.events.TimeEvent) is dispatched on MediaPlayer instances on three occasions:

TimeEvent.CURRENT_TIME_CHANGE is dispatched when the time property of the MediaPlayer has changed (e.g., your video has advanced, and you want to update a progress bar).

TimeEvent.COMPLETE is dispatched when the playback of the MediaElement currently playing back in the MediaPlayer is complete (e.g., when your video has ended).

TimeEvent.DURATION_CHANGE is dispatched when the duration of the MediaElement currently playing back in the MediaPlayer has changed, for example, when you swap out associated MediaElement instances (when you change which MediaElement instance is stored in the media property), or advance MediaElements in a SerialElement.

The code to listen for, and trace out the details of, a TimeEvent is:


mediaPlayer.addEventListener ( TimeEvent.CURRENT_TIME_CHANGE , onTimeEvent ) ;
mediaPlayer.addEventListener ( TimeEvent.COMPLETE , onTimeEvent ) ;
mediaPlayer.addEventListener ( TimeEvent.DURATION_CHANGE , onTimeEvent ) ;
function onTimeEvent ( evt : TimeEvent ) : void
{
		trace ( “onTimeEvent () , evt.name: “ + evt.name + “ , evt.time : “ +
evt.time ) ;
}

MediaPlayerCapabilityChangeEvent
The MediaPlayerCapabilityChangeEvent (org.osmf.events.
MediaPlayerCapabilityChangeEvent) is dispatched on MediaPlayer instances when the capabilities of the instance have changed.

MediaPlayerCapabilityChangeEvent.CAN_PLAY_CHANGE is dispatched on MediaPlayer instances when the playable state of the media loaded into the associated MediaElement changes. The value is either true (e.g., when your video has loaded and can begin playback), or false (e.g., when your video can no longer be played).

MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE is dispatched on MediaPlayer instances when the seekable state of the media loaded into the associated MediaElement changes. The value is either true (the media is now seekable) or false (the media is not seekable).


mediaPlayer.addEventListener ( MediaPlayerCapabilityChangeEvent.CAN_LOAD_CHANGE ,
onCapabilityChange ) ;
mediaPlayer.addEventListener ( MediaPlayerCapabilityChangeEvent.CAN_PLAY_CHANGE ,
onCapabilityChange ) ;
mediaPlayer.addEventListener ( MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE ,
onCapabilityChange ) ;
function onCapabilityChange ( evt : MediaPlayerCapabilityChangeEvent ) : void
{
		trace ( “onCapabilityChange () , evt.enabled : “ + evt.enabled ) ;
}

MediaPlayerStateChangeEvent

The MediaPlayerStateChangeEvent (org.osmf.events. MediaPlayerStateChangeEvent) is very useful at informing us in changes to the playback state of the media controlled by MediaPlayer instances. To listen for this event on MediaPlayer instances, and trace out the useful information from the event, we can use the following code:


mediaPlayer.addEventListener ( MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_
CHANGE , onMediaPlayerStateChange ) ;
function onMediaPlayerStateChange ( evt : MediaPlayerStateChangeEvent ) : void
{
		trace ( “onMediaPlayerStateChange () , evt.state : “ + evt.state ) ;
}

It then becomes important to know what the state property is set to on the MediaPlayerStateChangeEvent—so we know what state change led to the firing of this event. All possible state change values are available as public static constants on the MediaPlayerState class (org.osmf.media.MediaPlayerState).

If state =... That Means...
MediaPlayerState.PLAYING The media is playing.
MediaPlayerState.LOADING The media is loading.
MediaPlayerState.BUFFERING The media is buffering.
MediaPlayerState.UNINITIALIZED The MediaPlayer is empty (there is no loaded media).
MediaPlayerState.READY The media has completed loading and is ready for playback; or the media has
completed playback, has rewound, and is ready for playback again.

About The Authors

Photo of author R Blank

R Blank

R Blank is CTO of Almer/Blank, an Adobe Solution Partner based in Venice, California, that specializes in video and application development for the Flash platform. He is also the Training Director at the Rich Media Institute, the Adobe Authorized Training Center that he co-founded. As well, R serves on the faculty. His personal blog is RBlank.com.

Recommended Book

Photo of Book: ActionScript 3.0

If you want to build interactive applications on the desktop, in the browser, or on mobile devices, this new edition of the ActionScript 3.0 Bible is all you need.


Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.

Getting Started with Visual Studio 2010

By Alessandro Del Sole

16,952 Downloads · Refcard 118 of 151 (see them all)

Download
FREE PDF


The Essential Visual Studio 2010 Cheat Sheet

The Visual Studio 2010 Refcard focuses on the new features in this release and the most common keyboard shortcuts. It will get you started with the IDE and show you how to create, build and debug applications. Youll learn about the WPF Code Editor, which has improved extensibility and code reusability. Youll learn about the "Generate from Usage" tool. Youll also learn about drag and drop data binding with WPF and Silverlight. This Refcard is the perfect companion for the .NET developer working in Visual Studio 2010, whether its WPF, Silverlight, C#, VB, or F# development.
HTML Preview
Getting Started with Visual Studio 2010

Getting Started with Visual Studio 2010

By Alessandro Del Sole

INTRODUCTION

The new version of the Visual Studio 2010 Integrated Development Environment ships with a number of new important features. Such features are both related to the IDE architecture and to the coding experience, with the addition of new tools as well. This Refcard is a quick reference to the most important new features and instruments in Visual Studio 2010, also providing tips to most common shortcuts.

STARTING WITH VISUAL STUDIO 2010

Visual Studio 2010 is the developer tool used for creating .NET applications. There are different editions which cover every need, such as the Ultimate edition or the free Express editions (the latter are specific for hobbyists and students).

Starting the IDE

When you run Visual Studio 2010, the first thing you notice is a new Start Page which provides shortcuts, organized into tabs, to lots of learning resources about programming different Microsoft technologies with Visual Studio. These include the .NET Framework and programming languages, data platform, cloud computing or tools for teams. The following figure shows how the Start Page looks:

Visual Studio 2010 face

Visual Studio 2010 offers a convenient way for managing the most recently used projects by simply right-clicking each project name in the list. With this action you can pin or remove items from the list itself.

Creating applications

You create .NET applications in Visual Studio 2010 by first creating projects. A project is the place where all the parts composing your application, such as code, libraries, dialogs, pages and resources, reside. An application can be composed of one or more projects. Multiple projects bound together are combined into a Solution. Thus, the first step is creating a new project. You accomplish this by selecting the New|Project command from the File menu. This will show the New Project dialog which looks like this:

Visual Studio 2010 face2

As you can see, there are a number of available project types, grouped by programming language or by typology. As you can see from the above figure, the programming language project types are sub-grouped by technology. Once you have selected the desired project type, just assign a name and click OK. The Visual Studio documentation that ships with the product provides full descriptions for both Windows and Web projects.

In Visual Studio 2010 you can also target different versions of the .NET Framework (as shown in the figure above) or search specific project templates using the Search Installed Templates search box.

Building and debugging applications

You can build and run your executable application by pressing F5. This is common to both Windows and Web applications and will run your application with an instance of the Visual Studio debugger attached. Visual Studio provides a lot of debugging tools available in the Debug menu. For example, you can place breakpoints (also by pressing F9) or check for the value of local variables via the Locals tool window. If you don’t want to run the application under the debugger investigation, simply press Shift+F5.

You can quickly deploy your application using the ClickOnce technology, which you access via the Build|Publish command.

Browsing the documentation

You can access the Visual Studio documentation in different situations by pressing F1. For example you can get general information by pressing F1 anywhere or get specific help for an element in your code by selecting the code element (such as the name of a type) and, again, press F1. In Visual Studio 2010 the help system has been rebuilt completely and now allows you to browse the documentation inside your Web browser. The following figure shows an example:

Browsing the documentation

WPF-BASED CODE EDITOR

Most of the Visual Studio 2010 architecture now relies on Windows Presentation Foundation, the most recent technology from Microsoft for building rich client applications. If you are an existing Visual Studio developer this is something you immediately notice when running the IDE for the first time; it affects a number of areas such as the Start Page and tabbed dialogs or tool windows. The code editor is also built upon WPF which provides some great benefits, including:

  • Better text r endering
  • Code editor zoom by pr essing CTRL + mouse wheel
  • Automatic selection of all occurr ences of a word
  • Tabbed code dialogs can be undocked and tr eated like any other window outside the IDE
  • Improved extensibility: the code editor also takes advantage of MEF (Managed Extensibility Framework) to receive pluggable components. This allows hosting rich content inside the code editor, such as images, videos, WPF controls, comment adornments and so on.
  • Reusability: you can reuse the code editor as a component in your own Visual Studio add-ins.

You interact with the code editor via the IWPFTextView interface which is described in the MSDN Library. The following image shows how the WPF-based code editor looks:

WPF-based code editor

Notice that the zoom percentage is greater than 100%. This was accomplished simply by pressing CTRL + mouse wheel. A good number of code editor extensions are available in the Visual Studio Gallery Web site.

“GENERATE FROM USAGE” TOOL

In its continuous evolution, the Visual Studio environment has committed to offer even more sophisticated tools for helping developers write code. IntelliSense®, syntax highlighting, and auto-completion are just a few examples. It previously lacked the ability to create new objects on the fly. With Visual Studio 2010 you can now create new objects while writing code. This is useful when you realize that you need an object that you did not consider before or that you need to extend an existing object with new members. This functionality is integrated into the code editor and is known as Generate From Usage; it is available for both Visual Basic and C#.

Creating new types on the fly

Let’s start describing Generate From Usage by creating a new Console application. Consider the following situation, in which the code attempts to create an instance of the Contact class that actually does not exist yet and pay attention to the error correction options provided by the IDE:

IDE

Click Generate ‘Class Contact’ and Solution Explorer you will notice the presence of a file named Contact.vb (or .cs in C#) which contains the empty definition of the new class.

Hot Tip

The class declaration gets the default visibility modifier, according to the current programming language, which is Friend for Visual Basic and Internal for C#. You need to change this manually if you want to expose the class outside the assembly.

Now you can populate your class with new members, like in the following figure, where the code attempts to assign a non-inexistent property, but the IDE provides the possibility of generating a property or a field:

IDE2

If you select the first option, Visual Studio will add a property named LastName of type String to the Contact class. Similarly you can add both instances and shared methods on the fly. It is worth mentioning that Visual Studio:

  • generates members of the appropriate type when possible.
  • is able to generate interfaces and methods referring to delegates according to the current scenario. When generating such methods, it is able to add the appropriate signature.

You saw how to create a class, which is the default type, and members with default visibility. But you can do more with Generate From Usage as explained in next subsection.

Creating different kinds of types

There are situations in which you need to create different kinds of objects, such as structures or enumerations. Generate From Usage makes this task easy. For example, you might want to create a new structure. If you type the following line of code:


Dim someData As New CustomData

the IDE marks CustomData as non-existent. From the error correction suggestions popup, simply select Generate New Type. This will prompt you with the Generate New Type dialog shown in the next figure:

Type dialog

Here you can:

  • Provide the new object’s visibility by setting the Access property
  • Decide what kind of object you want to cr eate from the Kind property
  • Add the new member to a dif ferent project in your solution via the Project combo box
  • Create a new code file or add the new object to an existing code file inside the File Name box

Simply click OK when you are done and the new object will be added to your solution according to the specified settings. At this point you can add new members as described in the previous section.

WPF & SILVERLIGHT: DRAG AND DROP DATA-BINDING

Visual Studio 2010 introduces an important feature for data development to both WPF and Silverlight: drag and drop data-binding. This technique has been very popular in the past among Windows Forms developers since it allows creating data forms quickly and easily. In order to make the data development experience easier in modern client technologies, such a technique is now available for WPF and Silverlight. In WPF full support is offered for DataSets and ADO.NET Entity Framework. With full support we intend complete UI and codebehind code generation. Support is also offered for custom business objects or different data sources such as LINQ to SQL or WCF Data Services, but only on the UI side, meaning that you need to write all the data access code from scratch. In Silverlight you don’t have DataSets, so you can use this kind of data-binding with Entity Framework and custom objects.

Hot Tip

The drag and drop data-binding is also available for WPF 3.5 and Silverlight 3 projects.

Creating the data-bound interface

Whatever your data source is, you may open the Data Sources window and then simply drag your desired data item from the window onto the designer surface, as it was done previously in Windows Forms applications. The following figure provides an example based on the Entity Framework as the data source:

figure2

Hot Tip

The Data Sources window in Visual Studio 2010 provides full support for entities exposed by the Entity Framework.

As in older technologies, you can still create grid views or details views and you are allowed to replace the default controls with different ones. You can drag an entire object to create a view or a single object onto an items container control such as the ListBox for creating lists.

Hot Tip

Visual Studio adds controls to the user interface depending on the version of the .NET Framework you are targeting. For example, if you want to create a grid view, Visual Studio uses the DataGrid control in .NET 4 and a ListView control in .NET 3.5.

Dragging and dropping the data is just the first step since you obviously need some code.

A tour of the code

When you use the drag and drop binding, Visual Studio generates some useful code for you. This not only refers to the user interface and controls, but also to querying data. On the XAML side, it first generates the appropriate CollectionViewSource objects acting like “bridges” between data and UI:


<Window.Resources>
	  <CollectionViewSource x:Key=”CategoriesViewSource” d:DesignSo
urce=”{d:DesignInstance my:Category, CreateList=True}” />
	  <CollectionViewSource x:Key=”CategoriesProductsViewSo
urce” Source=”{Binding Path=Products, Source={StaticResource
CategoriesViewSource}}” />
	</Window.Resources>

Next it generates data-bound controls, such as a DataGrid and Label/TextBox couples if considering the previous image (notice the Binding markup extension pointing to the bound property):


<DataGrid AutoGenerateColumns=”False” EnableRowVirtualization=”True”
Height=”128” HorizontalAlignment=”Left” ItemsSource=”{Binding}”
Name=”CategoriesDataGrid” RowDetailsVisibilityMode=”VisibleWhenSelect
ed” VerticalAlignment=”Top” Width=”248”>
	<DataGrid.Columns>
		<DataGridTextColumn x:Name=”CategoryIDColumn”
Binding=”{Binding Path=CategoryID}” Header=”Category ID”
Width=”SizeToHeader” />
		<DataGridTextColumn x:Name=”CategoryNameColumn”
Binding=”{Binding Path=CategoryName}” Header=”Category Name”
Width=”SizeToHeader” />
		<DataGridTextColumn x:Name=”DescriptionColumn”
Binding=”{Binding Path=Description}” Header=”Description”
Width=”SizeToHeader” />
	</DataGrid.Columns>
  </DataGrid>
…
	<Label Content=”Product ID:” Grid.Column=”0” Grid.Row=”0”
HorizontalAlignment=”Left” Margin=”3” VerticalAlignment=”Center” />
	<TextBox Grid.Column=”1” Grid.Row=”0” Height=”23”
HorizontalAlignment=”Left” Margin=”3” Name=”ProductIDTextBox”
Text=”{Binding Path=ProductID, Mode=TwoWay,
ValidatesOnExceptions=true, NotifyOnValidationError=true}”
VerticalAlignment=”Center” Width=”100” />
…

It is worth mentioning that Visual Studio also maps data types to the appropriate controls. A typical example is when you have data of type System.DateTime that is represented via a DatePicker control (available in .NET 4 only). On the managed code side, Visual Studio generates some starting code for querying data. In case you use the Entity Framework as the Data Access Layer, the generated code looks like this (continuing the example from the previous image):


Class MainWindow
	Private Function GetCategoriesQuery(ByVal NorthwindEntities As _
										WpfApplication1.
NorthwindEntities) _
										As System.Data.Objects.
ObjectQuery(Of WpfApplication1.Category)


	Dim CategoriesQuery As System.Data.Objects.ObjectQuery(Of
WpfApplication1.Category) =
		   NorthwindEntities.Categories
		‘Update the query to include Products data in Categories. You
can modify this code as needed.
		CategoriesQuery = CategoriesQuery.Include(“Products”)
		‘Returns an ObjectQuery.
		Return CategoriesQuery
	End Function
	
	Private Sub Window_Loaded(ByVal sender As System.Object,
							  ByVal e As System.Windows.
RoutedEventArgs) _
							  Handles MyBase.Loaded
		Dim NorthwindEntities As WpfApplication1.NorthwindEntities =
			New WpfApplication1.NorthwindEntities()
		‘Load data into Categories. You can modify this code as
needed.
		Dim CategoriesViewSource As System.Windows.Data.
CollectionViewSource =
			CType(Me.FindResource(“CategoriesViewSource”), System.
Windows.Data.CollectionViewSource)
		Dim CategoriesQuery As System.Data.Objects.ObjectQuery(Of
WpfApplication1.Category) =
		  Me.GetCategoriesQuery(NorthwindEntities)
		CategoriesViewSource.Source = CategoriesQuery.
									  Execute(System.Data.Objects.
MergeOption.AppendOnly)
   End Sub
End Class

This will allow loading some data when you run the application. Once you have your starting code, you can write your own queries or extend the auto-generated code with additional features, such as Insert/Update/Delete operations or provide data navigation functionalities.

WPF & SILVERLIGHT: MULTI-TARGETING DESIGNER

In previous versions of Visual Studio the design-time experience for WPF and Silverlight developers did not offer specialized design tools. For WPF developers, the IDE lacked some tooling familiar to Windows Forms developers. Visual Studio 2008 introduced some improvements to the WPF design experience, like the ability to drag controls from the toolbox and drop them onto the designer surface, or the possibility to access event handlers by double-clicking the controls. But no support was available for setting special properties inside the Properties Window (e.g. brushes) so developers needed to manually write the code to set them. For Silverlight developers, things were even worse, in that you had neither drag and drop support nor design time support such as adjusting the application layout, so everything had to be set in code. Although Visual Studio is a developer tool, Microsoft Expression Blend is the tool best suited for deep customization of the user interface. While lots of developers use only Visual Studio to create the user interface for their applications, the need for better VS designer program was paramount. This is what happened with the release of Visual Studio 2010. In the next section you get an overview of the new and improved features, while later you will get information about how this targets multiple .NET Framework versions.

Improved experience

With Visual Studio 2010, both the WPF and Silverlight esigners now provide a full design-time experience and, most importantly, both technologies share the same tools. This means that you have the same instrumentation available for both WPF and Silverlight projects. You now have full support for dragging and dropping controls from the toolbox, for rearranging controls on the controls’ surface and you can also set complex properties within the Properties Window. The following figure represents such a description with regard to a WPF project:

figure3

If you try to do this inside a Silverlight project, you get exactly the same result and tools available. Notice how you now have a new color picker editor available for properties of type brush, which allows specifying the brush color, its type (e.g. a gradient or an image) and manually entering the color code. Prior to Visual Studio 2010 this had to be performed by writing pure XAML code. There are a number of other improvements in this area that are listed below.

Setting grid columns and rows

You can easily set rows and columns within a Grid control by selecting the RowDefinitions and ColumnDefinitions properties in the Property Window and then by taking advantage of a new dialog that looks like the following figure:

figure4

You simply click Add, then set properties for each row or column, such as the Height or Width.

Searching for a property

The Properties Window has been enhanced with a number of new features. You got a taste of this in the previous section when discussing how to set properties of type Brush. Another interesting addition is that you can now search for a specified property by writing its name in the search box at the top of the window. Also, you do not need to write the entire property name since Visual Studio filters the property list as you type characters inside the search box:

figure5

This way you can easily reach and set the properties you want to assign.

Hot Tip

The search field is also available in the Events tab of the Properties Window.
Setting controls’ fonts

In Visual Studio 2010 you can now easily set font properties to controls supporting fonts via an integrated tool inside the Properties Window.

Hot Tip

This is available only when you enable the Categorized view.

For instance, you can select the font from a combo box and then set text alignment, size and weight all together, as shown in the following figure:

figure6
Visually setting data-binding and resources

The Properties Window also improves the way you assign data-bound properties or resources. You select the data-bound property for your control and then you can easily use the Binding popup as follows:

  1. Select your data source. This can be the DataContext—another control or a resource as shown in the followingfigure:

    figure7

  2. Switch to the Path tab in order to select the property you wish to be bound;
  3. Select any value converter you want to apply via the Converter tab; and
  4. Finally go to the Options tab and apply any other additional options. This is really impressive in that you have a great number of available properties such as data error validation or triggering property changes.

You can apply resources similarly. For example, if you defined a style for a button and then you want to apply such a style, just right click the Style property in the Properties Window and select Apply Resource. This will provide a useful popup where you will be able to pick both default and local resources, as demonstrated in the following figure:

figure8

You can also choose between static and dynamic resources and you are offered a preview of the result you get once the resource is applied.

Multiple .NET Framework versions targeted

Visual Studio 2010 ships with integrated support for Silverlight 3 but it also supports Silverlight 4 when you install the appropriate developer tools. The good news is that all the stuff you have seen so far, including the drag and drop databinding, is available for both .NET Framework 3.5 SP 1 and 4.0 in Visual Studio 2010. This is what is usually referred to as multi-targeting, when talking about the designer. This basically means that you can create applications for WPF 3.5, WPF 4, Silverlight 3 and 4 taking advantage of all the new designer features independent of the technology or its version. If you want to check this out by yourself, simply create a new WPF or Silverlight project and in the New Project dialog select the .NET Framework 3.5 as the target Framework. You will notice no difference in the designer if compared to .NET 4.

COMMON SHORTCUTS AND TIPS

Visual Studio 2010 offers both shortcuts for quick access to common tools and instruments that you may find really useful. This section provides information on both topics.

Common shortcuts

  • Start the application in debugging mode by pr essing F5 or without attaching the debugger by pressing Shift+F5
  • Save all files in your solution by pr essing Ctrl+Shift+S
  • Build your solution by pr essing Ctrl+Shift+B
  • Run your application without the debugger by pr essing Shift+F5
  • Show the toolbox by pr essing Ctrl+Alt+T
  • Navigate to a specific member definition by pr essing Ctrl+
  • Comment multiple line of codes by pr essing CTRL+K and CTRL+C in sequence or uncomment lines by pressing CTRL+K and CTRL+U in sequence
  • Show up the Properties window by pressing F4
  • Select code blocks by pr essing ALT + mouse
  • Place a breakpoint by pressing F9 on the specified line of code

Common tips

  • Download and manage Visual Studio extensions via the Tools|Extension Manager tool
  • Add menu items for running external tools via the Tools|External Tools command
  • Add IntelliSense code snippets within the code editor by pr essing Ctrl+K or right-click and then Insert Snippet
  • Export project or item templates in or der to create reusable templates with File|Export template
  • Find all references of a type or member by performing right click inside on a member inside the code editor and then selecting Find All References

About The Authors

Photo of author Alessandro Del Sole

Alessandro Del Sole

Alessandro Del Sole, Microsoft Most Valuable Professional (MVP) for Visual Basic since 2008, is well known throughout the global Visual Basic community. The author of four books about .NET development with Visual Studio, he is a community leader on the Italian Visual Basic Tips and Tricks (www.visual-basic.it) web site that serves more than 42,500 VB developers. He is also a frequent contributor to the MSDN Visual Basic Developer Center (msdn.com/vbasic). He enjoys writing articles on .NET development, writing blog posts on both his Italian and English blogs, and producing instructional videos. You can find him online in forums or newsgroups.

Recommended Book

Photo of Book: Visual Basic 2010

This book’s broad coverage includes advanced features such as generics and collections; a thorough introduction to the Visual Studio 2010 IDE and Visual Studio Team System; a full section on data access with ADO.NET and LINQ; practical overviews of WPF and WCF; coverage of web and cloud development with Silverlight and Azure; and advanced topics such as multithreading, testing, and deployment.

Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.

Free Fitnesse Cheat Sheet - DZone's 100th Refcard!!

Fitnesse is an open source automated framework for software testing. With this DZone Refcard, you'll easily create and edit platform independent tests. Download your free copy now!

0 replies - 25261 views - 05/24/10 by Lyndsey Clevesy in Announcements

Getting Started with Fitnesse

By Erik Pragt

9,933 Downloads · Refcard 100 of 151 (see them all)

Download
FREE PDF


The Essential Fitnesse Cheat Sheet

"Fitnesse is an open source automated framework created for software testing purposes. It stimulates collaboration in software development by providing a Wiki-powered test framework which enables customers, testers and programmers to easily create and edit tests in a platform independent way. This DZone Refcard will provide an introduction to Fitnesse so that you can begin to easily create and edit tests in a platform independent way. In addition to an overview of the framework, you’ll learn how to configure Fitnesse, how to perform BDD testing, and more."
HTML Preview
Getting Started with FitNesse

Getting Started with FitNesse

By Erik Pragt

ABOUT FITNESSE

FitNesse is an open source automated framework created for software testing purposes. It stimulates collaboration in software development by providing a WIKI powered test framework which enables customers, testers and programmers to easily create and edit tests in a platform independent way. FitNesse is based on Ward Cunninghams’s Framework for Integrated Test (FIT) and is now further developed by Robert C. Martin.

FitNesse is designed to support functional testing (also know as acceptance testing) by being integrated on a business level. This is different from testing on a User Interface level, where tools like Selenium, HtmlUnit, Watir and many others are used.

FITNESSE OVERVIEW

FitNess

FitNesse works by executing Wiki pages which call custom written Fixtures. Fixtures are a bridge between the Wiki pages and the System Under Test (SUT), which is the actual system to test. These Fixtures can be written in many programming languages like Java, C#, and Ruby.. Whenever a Wiki test is executed, the Fixtures works by calling the System Under Test (SUT) with the appropriate parameters, execute a piece of business logic in the software system, and pass the results (if any) of the SUT back to the Wiki front-end, which in turn will visually indicate if a test has passed or not.

FitNesse has two test systems, SLIM and FIT. FIT is the older test system, and is no longer actively developed. However, recent plans indicate that FIT might be further developed. Because of the complexity to maintain and support FIT on different platforms, SLIM was created. SLIM is a lightweight version of the FIT protocol. One of the design goals of SLIM was to easily port implementations to different languages. Also, in contrast to FIT, SLIM doesn’t require any dependencies on the FitNesse framework in the Fixtures code, which makes writing fixtures more easy.

INSTALLING FITNESSE

While FitNesse is available in multiple languages (see http://www.fitnesse.org/FrontPage.FitServers), this Refcard will focus on the most actively developed version, which is the Java variant. You’ll need Java 6 to run the most recent version of FitNesse.

Below are the steps to install FitNesse:

  1. Download the most recent version from http://www.fitnesse.org/FrontPage.FitNesseDevelopment.DownLoad
  2. Run “java -jar fitnesse.org”. FitNesse will extract itself and will try to run itself on port 80.
  3. Note: when running on port 80 fails, e.g. because of security constraints or the port is already in use, try to run FitNesse by typing “java -jar fitnesse.jar -p 9090”. This will start FitNesse on port 9090
  4. Access FitNesse by pointing your web browser to http:/localhost:<port-number> to see the FitNesse Front page

FITNESSE COMMAND LINE OPTIONS

FitNesse requires very little configuration, but does provide some options, which are displayed below.


Usage: java -jar fitnesse.jar [-pdrleoa]
		-p <port number> {80}
		-d <working directory> {.}
		-r <page root directory> {FitNesseRoot}
		-l <log directory> {no logging}
		-e <days> {14} Number of days before page versions expire
		-o omit updates
		-a {user:pwd | user-file-name} enable authentication.
		-i Install only, then quit.
		-c <command> execute single command.

TESTS AND SUITES

FitNesse has the concept of Suites and Tests. Suites are sets of Tests, which is a way to organize the Tests. As an additional benefit, when executing a Suite, all Tests within the Suite are executed.

CREATING THE SUITE

To create a new FitNesse suite:

  • Go to the FitNesse Front page at http://localhost:9090
  • Click Edit in the left menu
  • Type the name of the Suite after the existing text, e.g. JukeboxSuite

Important: FitNesse will only create links when the text is written in CamelCase. This means that every page needs to start with an uppercase character and at least one other letter in the word is written in uppercase.

  • Click save
  • Click on the question mark [?] next to the JukeboxSuite text
  • Press save

An empty Suite has now been created, which is indicated by the ‘Suite’ text on top of the left menu.

Note: FitNesse marks a page as a Suite automatically when it starts or ends with Suite. A Wiki page can also manually be set as an Suite in the page properties by clicking ‘Properties’.

CREATING A NEW FITNESSE TEST

The Decision Table is the default test table style used by FitNesse. When not specifying a table prefix, FitNesse decides it is a Decision Table. An example Decision Table is used below to assert the proper conversion of payments into credits.

Creating a Test is similar to creating a new Suite:

  • When in a Suite, click ‘Edit’ in the left menu
  • Clear the text area and type the name of the Test, e.g. PaymentTest
  • Click save
  • Click on the question mark [?] next to the PaymentTest
  • Clear the text area and replace the text by the following:

!4 Story: the amount you pay determines the received credits.
!|credits for payment|
|payment|credits?|
|.25 |1 |
|1 |4 |
|5 |20 |

  • (There are multiple types of test styles, but the above is a Decision Table)
  • Press ‘Save’

Your first test has now been created, including some markup. This markup is ignored when executing the Test; only tables are executed. When you execute this test by clicking on ‘Test’ in the left menu, your test will fail with an error. To get the test to work, we need to do two more things: write the Fixture and configure FitNesse correctly.

WRITING THE FIXTURE

The Fixture will be the layer between the production code (the Subject Under Test) and the FitNesse pages. There are multiple types of Fixtures, and to support the Test above, a Decision Table Fixture is needed. Consider the following code to test:


package jukebox.sut;
public class JukeBox {
   public int calculateCredits(double payment) {
      return payment * 4;
   }
}

The Fixture to test this class looks like this:


package jukebox.fixtures;
import jukebox.sut.JukeBox;
public class CreditsForPayment {
	private double payment;
	private int credits;
	public void execute() { // executed after each table row
	this.credits = new JukeBox().calculateCredits(payment);
	}
	public void setPayment(double payment) { // setter method
	this.payment = payment;
	}
	public int credits() { // returning function because of question
	mark in the test return this.credits;
	}
}

The Fixture is created from the FitNesse page, and for each row:

  • First the setters are called (in this case setPayment),
  • Then the execute is called to do call the SUT
  • Then the result is retrieved from the Fixture and compared to the FitNesse expectation.

CONFIGURING FITNESSE

By default, FitNesse uses FIT as it’s default Test System. Since we want to use SLIM instead, this needs to be changed. We can change this by editing the Test page again, and add the following line on top of the page:


!define TEST_SYSTEM {slim}

This line tells FitNesse to use the Slim instead of FIT, and allows FitNesse to execute our Fixtures correctly.

What we also need to do is set the classpath. Please check your IDE to see what the output classpath of the project is, and add that to the following line:


path <your-classpath-here>

As an example of the above, the following would tell FitNesse to use the libraries in the development folder:


!path c:\Development\spring.jar
!path c:\Development\hibernate.jar

The last thing we need to do is tell FitNesse in which package to find the Fixture. This can be done either by prefixing the name of the fixture class in the Wiki, or use a special kind of Table, the Import Table.

Add the following to your FitNesse Test, above the ‘credits for payment’ section:


|import|
|jukebox.fixtures|

Pressing the ‘Test’ button in the left menu will instruct FitNesse to execute the Test. The FitNesse Fixture will call the SUT, and color the Wiki page according to the test results. This will result in a green Wiki table representing a correctly executed test as can be seen in the following image.

Wiki

RUNNING FITNESSE TESTS

Tests, however well written, can fail due to numerous reasons. The test can be wrong, the results can be asserted incorrectly, or the Subject Under Tests is incorrect and returns the wrong results. To find out what is causing this, tests can be debugged. When you want to debug a test, start by adding ?responder=test&remote_debug=true to the URL for the test. After starting the test in FitNesse, start a remote debugging process in the right port. (Port 8000 if you are using the default settings for REMOTE_DEBUG_COMMAND, though this can be changed by customizing the REMOTE_DEBUG_COMMAND in your Wiki)

ORGANIZING TESTS

To structure your Tests in a good way it’s a good idea to create Suites per area of functionality. For example, a Suite can be created for Managing Inventory (InventoryManagementSuite), for Sales (SalesSuite) and for Accounting (AccountingSuite). The Tests should be organized functionality wise, not technology wise. So don’t create a WebserviceTestSuite, or an XmlParseTestSuite, because in that way you tie your tests too much to the implementation and focus less on the business functionality.

Organizing your tests in a functional way allows you to run the tests in a finer granularity, where you can choose to either run all of the Suites, some of the Suites, or just a single Test.

Hot Tip

Organizing your tests in a functional way allows you to run the tests in a finer granularity, where you can choose to either run all of the Suites, some of the Suites, or just a single Test.

SLIM TEST TABLE STYLES

The first cell of a slim table determines what kind of Test Table it is. Here are the table types provided by FitNesse:

Table Name Description
Decision Table Supplies the inputs and outputs for decisions.
Query Table Supplies the expected results of a query.
Subset Query Table Supplies a subset of the expected results of a query.
Ordered query Table Supplies the expected results of a query. The rows are expected to be in order.
Script Table A series of actions and checks. Similar to Do Fixture.
Scenario Table A table that can be called from other tables.
Table Table A very flexible table which can be used for almost everything.
Import Add a path to the fixture search path.
Comment A table which will not be executed.
Library Table A table that installs fixtures available for all test pages.

DECISION TABLE

The decision table is the default table style used by FitNesse. That is, when not specifying a prefix, FitNesse decides it is a Decision Table. As an alternative, you can prefix the Fixture name definition in the Test page with ‘decision:’ or ‘dt:’, so the example below would look like: ‘decision:cr edits for payment’. An example of a decision table is shown below:


!3 Payment test
The amount you pay determines how many credits get added to your balance.
!|credits for payment|
|payment |credits?|
|.25 |1  |
|1.0 |5  |
|5.0 |25 |
|10  |60 |

The English text above outside the table is ignor ed by

FitNesse and only serves a documenting purpose. The (pipe separated) table however is executed by FitNesse. There are 3 items in the table: the fixture name (credits for payment), the header (payment & credits), and the data (the r est of the table).

Please note the exclamation mark (!) in the first row. While not explicitly needed in this example, it prevents FitNesse from interpreting camel case words as page links. Putting a exclamation mark in the first row will leave any camel case words as-is and will not turn them into page links.

The header row consists of two header names, payment and credits. Normally, each header corresponds to a set function. The ‘credits’ header contains a ? Decision Tables consider this to be an output and so calls it as a function. The return value of that function is compared to the cell contents and the cell is colored green if it matches the cell, or red if it doesn’t.

When executing this Test, FitNesse will look in the classpath for a fixture named CreditsForPayment. For each line in the table, FitNesse will call a setter for payment on the Fixture (setPayment(double payment)). After all ‘set’ functions have been called, the ‘execute’ method will be called by FitNesse. In the example below, the ‘execute’ method does the actual work. After that, the ‘credits’ function will be called (public int credits()), and the result of that call will be evaluated by FitNesse and colored accordingly. The code required to make this work is shown below.


package jukebox.fixtures;
public class CreditsForPayment {
	private double payment;
	private int credits;
	public void setPayment(double payment) {
	this.payment = payment;
	}
	public void execute() {
	this.credits = JukeBox.calaculateCredits(payment)
	}
	public int credits() {
	return credits;
	}
}

Optional Functions

Decision tables have the option to implement optional functions, which will be called if they are defined in the Fixture. In the example above, the execute function is used. Decision tables know 3 optional functions:

Function Description
reset Called once per row before any set or output functions care called.
execute Called once per row after all set functions have been called, but just before the first output (if any) is called.
table Is called after the constructor and before any rows are processed. It is passed the contents of the complete table in the form of a list of lists that contain all the cells except for the very first row.

QUERY TABLE

Query tables are, as the name implies, meant to query for data. There are currently 3 kinds of query tables, which are almost identical, but with some notably exceptions.

Fixture Description
Query A standard query table, which compares the complete set of data in and unordered way.
Subset query Only those rows defined in the table need to be in the Fixture result.
Ordered query The order of the rows in the table must be in the same order as the rows returned by the query.

A query table is used to compare the results of a query. This is helpful when you only need to make assertions about data, instead of also manipulating data in the system. An example:


|Query:songs from artist|Led Zeppelin|
|title|artist|duration|
|Stairway to Heaven|Led Zeppelin|8:36|
|Immigrant Song|Led Zeppelin|2:25|

The following code describes the fixture:


package jukebox.fixtures;
import static util.ListUtility.list;
import java.util.*;
import jukebox.sut.Song;
public class SongsFromArtist {
	String artist;
    public SongsFromArtist(String artist) {
	  this.artist = artist;
    }
	public List <Object> query() {
	  List result = new ArrayList();
	  for (Song song : JukeBox.findSongsFromArtist(artist)) {
		result.add(list(
			list(“title”, song.getTitle()),
     		list(“artist”, song.getArtist()),
			list(“duration”, song.getDurationInUserFriendlyFormat())
		 )
		);
	  }
	  return result;
	}
}

Note that the list function simply builds an ArrayList from it’s arguments. It’s in the ListUtility class, which is included in the fitnesse.jar.

The Fixture class must have a query method that returns a list of rows. Each row returned by the query method is a list of fields. Each field is a two-element list composed of the field name and it’s value as a String.

Each row in the table is checked to see if ther e is a match in the query response. The results of the comparison are colored accordingly, and are checked for extra or missing records. The order of the rows is irrelevant in the query tables.

If a “table” method is declared in the fixture it will be called before the query function is called. It will be passed a list of rows which are themselves lists of cells. This is the same format as the table method of Decision table.

SCRIPT TABLE EXAMPLE

Script tables are one of the most flexible table styles and can be used for scenario or story based testing. When using a Script table, each statement in the FitNesse test will refer to a method of the fixture used or to an earlier defined scenario. Each statement can be prefixed by one of the Script Table keywords (see below). An example:


|script:current account |
|check	   |cash balance should be |0.0  	     |
|deposit   |.25                        	  	     |
|check 	   |cash balance should be |.25			 |
|deposit   |.75                        			 |
|check     |cash balance should be |1  			 |
|$balance= |total deposits             			 |
|ensure    |withdraw               |1  			 |
|note      |account should not allow negative balance|

Java code


public class CurrentAccount {
	public double cashBalanceShouldBe() { .... }
	public void deposit(double amount) { .... }
	public boolean withdraw(double amount) { .... }
	public double totalDeposits() { .... }
}

When executing this test, a function alone in a row will turn red or green if it returns a boolean. Otherwise it will simply remain uncolored.

Script Table Keywords

check Followed by a function call. The last cell of the row is the expression to expect of the function call.
check not Followed by a function call. The last cell of the row is the expression to not be matched by what the function actually returns.
ensure Followed by a function call which return boolean (true for green, red for false)
reject Opposite of ensure, meaning true is red, false is green.
note All other cells in that row will be ignored. Alternatives to note are if the first cell is blank, or if the first cell begins with # or *.
show Followed by a function call. A new cell is added after the test has run which will contain the return value of the function. Good for debugging.
start The rest of the row is the name and constructor arguments for a new actor (a fixture) which replaces the current actor.

Hot Tip

If a symbol assignment (see below) is in the first cell, e.g. $name= , then it should be followed by a function. The return value of the function is assigned to the symbol and can be used in later calls to other functions.

IMPORT TABLE

An Import Table is not a test table. Instead, it tell the underlying test system (the Slim Executor) which classpath prefixes to use when searching for the Fixtures. This way, the fully qualified name (the name of the class including the package name) of the Fixture can be replaced by only the classname of the Fixture.

An Import Table can be used like the following:


|import|
|com.path.to.fixture|
|ClassNameOfFixture |

COMMENT TABLE

Similar to Import Tables, Comment Tables are not Test Tables. As the name implies, Comment Tables are used to comment out tables. Commented tables are not executed.


|comment|
|this table| is not|executed|

LIBRARY TABLE

A Library Table can be used to make functions available for all pages underneath the page the Library Table is defined in. Whenever a method is called that is not available on the Fixture, then all Fixtures defined as libraries are scanned for that function so that it can be invoked.

Library tables can be defined by creating a Wiki table of which the first row contains the reserved word Library. All subsequent rows following the first are the names of fixtures. These Fixtures are located the same way in the classpath as normal Fixtures, so the rules of the Import Table apply here also. Library Tables can be used for common functionality which should be reused between tests. An example:


|Library|
|song creation|
|script|jukebox fixture|
|create song|Stairway to Heaven|
|play song|Stairway to Heaven  |

And the associated Fixture code:


public class SongCreation {
  public void createSongForArtist(String songName) {
    // song creation logic here
  }
}
public class JukeboxFixture {
  public void playSong(String songName) {
    playService.playSong(songName);
  }
}

The lookup strategy of functions is:

  • First try to find the function in the current Fixture and execute it.
  • If the function was not found, look it up in the System Under Test.
  • If the function was not found in the System Under Test, look in the list of defined libraries, in reversed order of creation. This means that the function is first looked up in the last defined library Fixture, then in the one before that, etc.

USING SYMBOLS

If a $<symbolName> appears in an output cell of a table, then that symbol will be loaded with that output. For example:


|DT:some decision table|
|input|output?|
|3|$V=|
|$V|8|
|9|$V|

The first row above loads the return value of the output function into the symbol V. The second row will load the previously stored value of V into the input. The third row compares the output with the previously stored value of the symbol.

FORMATTING CHEAT SHEET

FitNesse comes with an extensive set of formatting options to style the text in Wiki pages.

Character formatting

Comment #text
Italics "text"
Bold '''text'''
Style !style_<style>(text), e.g. !style_pass(passed!)
Strike-through --text--
Header !1 Title
!2 Header
!3 Small header
Bullet Lists [space]* Item one
[space][space]* Sub item one
[space][space]* Sub item two
Numbered lists (numbers will be incremented automatically) [space]1 Item one
[space]1 Item two
[space]1 Item three
Centering !c center this text
“As-is”/escaping !-text-!
“As-is” !<text>!
Formatted “as is” {{{text}}}

Line and Block Formatting

Horizontal Line -----
Note !note text
Collapsible section expanded !* [title]
multi-line Wiki text
*!
Collapsible section collapsed !*> [title]
multi-line Wiki text
*!
Hidden collapsible section !*< [title]
this is hidden, but still active
*!
Plain text table ![ my simple
table
]!
Literalized table ![:
first:Erik
last:Pragt
]!

Links and References

Page links - from root .RootPage[.Childpage]
Page links - sibling SameLevelPage[.ChildPage]
Page links - child or symbolic >ChildPage[.ChildPage]
Page links - from parent <ParentPage[.ChildPage]
Cross-reference !see AnyPagePath
“In page” label !anchor label-name
Jump to anchor - in-line
Jump to anchor - left-justified
Jump to anchor - in an alias
text #label-name text
.#label-name
[[text][#label-name]]
External links -web
-local
-alias
-alias
http://url-path http://files/somePath
[[text][/files’’’/localPath]]
[[text][AnyPagePath#label-name]]
Picture
- clickable
!img url-to-image-file
[[!img url-to-image-file][some-link]]
Contents List !contents
Contents Tree !contents -R
Content Sub-tree !contents -R2
Include page !include AnyPagePath

Variables

Variable Definition !define name {value}
Variable Usage ${name}
Expression Evaluation ${=expression=}

Global Variables

Global variables can be set by placing them in the Wiki pages, for example:


!define TEST_SYSTEM { slim }

Variable Definition !define name {value}
Variable Usage ${name}
Expression Evaluation ${=expression=}

BDD STYLE TESTING

Behavior Driven Development (or BDD) is an Agile software development technique that encourages collaboration between participants in a software project. BDD focuses on exposing internal logic (typically business rules) to review by stakeholder. As such, it’s a perfect match with FitNesse’s goals. FitNesse doesn’t have special support for Behavior Driven Development (BDD) style testing in the form of special Test Tables, but using a combination of Script and Scenario Tables provides the right tools to support the popular Given-When- Then style of testing User Stories.

Consider the following example:

Given a juke box with 0 credits
When I deposit .25
Then the juke box should show 1 credits

Due to the flexible nature of FitNesse and Script Tables, it’s easy to support a story like the one above. There are multiple ways to implement this in FitNesse, but one of the best ways is to use a combination of Plain Text Tables and Scenario Tables.

Plain Text Tables

Plain Text Tables can be used to surr ound plain text with ![ and ]! symbols to turn the text into tables. The good thing about the Plain Text Table is that it can be combined with the FitNesse tests tables, for example the Script table. This can be done by adding the ‘script’ tag after the ![ symbol. This would result in the following Wiki text:


![ script
Given a juke box with 0 credits
When I deposit .25
Then the juke box should show 1 credits
]!

As you can see in the story, there is a combination of text and parameters. Scenario tables with a parameterized style provide a good way of handling this.

Declaring Scenarios Using Parameterized Style

Instead of using pipe symbols to separate between function names and parameters, you can also declare a scenario by embedding underscores within the name of the scenario to represent variables. Each of the underscores represent an argument which are named in a comma separated list in the cell following the scenario name.


#page driver
|script|juke box|
|scenario|Given a juke box with _ credits and _ songs|credits,songs|
|set credits|@credits|
|set songs|@songs|

FitNesse will now invoke the scenario instead of looking for a method in a Fixture. The body of the scenario uses the supplied parameter names by prefixing them with an ‘@’ sign.

The body of the scenario type will be invoked against the page driver. The page driver can be defined by using the script tag. This needs to be defined before any scenarios are defined. The page driver is just a normal Script Fixture, and all functions defined in the scenario are executed against that Fixture.

Creating a Test like this can hide the details of the test and allows you to focus on a readable test while creating reusable scenarios in the process.

TRAINING

Neuri Ltd (http://neuri.co.uk) and jWorks (http://www.jworks.nl) offer training courses for FitNesse and provide professional training for Test Driven Development and Agile Acceptance Testing. On a regular basis, jWorks offers free Open Source Test Workshops to promote the usage of Automated Acceptance testing.

CONCLUSION

FitNesse provides an Open Source testing framework which is flexible enough to support most testing needs. An investment is needed to setup the test framework, but this investment leads to better software, less bugs and software which is easier to maintain. FitNesse allows to test quick and often, providing quick feedback on the health of the software being delivered without the need for any manual labor. This makes FitNesse a very valuable tool which would fit nicely in any software development project!

About The Author

Photo of author Erik Pragt

Erik Pragt

My name is Erik Pragt. I've been a software developer since the end of the 90's, and I worked for various companies, including ISP’s, Web Designers, a Medical Software Developer. I focus on Java (JEE, Maven, Wicket), Distributed Software Development, Agile Processes, Coaching, SCRUM and Testing (TDD), but I'm passionate about Groovy and Grails and I'm a strong believer in a place for Grails in the EE world!

Recommended Book

Fit

Using a realistic case study, Rick Mugridge and Ward Cunningham--the creator of Fit--introduce each of Fit’s underlying concepts and techniques, and explain how you can put Fit to work incrementally, with the lowest possible risk.


Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.

Download Your Free Grails Cheat Sheet Now!

New to Grails? Click here to download DZone's latest Refcard: Getting Started with Grails.

1 replies - 7427 views - 06/29/09 by Lyndsey Clevesy in Announcements

Getting Started with Grails

By Dave Klein

16,023 Downloads · Refcard 60 of 151 (see them all)

Download
FREE PDF


The Essential Grails Cheat Sheet

Grails is a full-stack web application framework built on top of popular open source frameworks such as Spring, Hibernate, Ant, and JUnit. This DZone Refcard takes you through a brief introduction of Grails, and helps you to set up your first Grails application in minutes. It serves as a handy reference manual for working with Grails Controllers, Services, Views and GSP taglibs. You also may enjoy these other DZone Refcardz on related topics: Spring Configuration and JUnit and EasyMock.
HTML Preview
Getting Started with Grails

Getting started with grails

By Dave Klein

Getting started with grails

Grails is a full-stack web application framework built on top of such tried and true open source frameworks as Spring, Hibernate, Ant, JUnit and more. By applying principles such as Convention over Configuration and Don't Repeat Yourself, and taking advantage of the dynamic Groovy programming language, Grails makes it incredibly easy to use these powerful tools. Grails doesn't reinvent the wheel; Grails makes a wheel that inflates itself and rolls where you want it to!

In case you are new to Grails, we'll start with a brief introduction, which should be enough to get you hooked and turn you into a Grails developer. That's when this Refcard will come in handy; it is a cheat sheet for Grails developers, a quick source for those things you keep having to go back to the docs to look up. Controllers, Services and Views with a detailed GSP taglib reference.

Installing Grails

Download the Grails archive from http://grails.org/download and extract it to a local directory. Set a GRAILS_HOME environment variable to that directory and add GRAILS_ HOME/bin to your path. (You also need a valid JAVA_HOME environment variable.) Now you're ready to go!

A Web App in the Blink of an Eye

To create a new Grails application, type:


$ grails create-app AutoMart

Now change to the AutoMart directory and create a domain class:


$ grails create-domain-class Car

Open AutoMart/grails-app/domain/Car.groovy and edit it, like so:


class Car {
	String make
	String model
	Integer year
}

Save this file, and run:


$ grails generate-all Car

Create-app and create-domain-class are Grails scripts. To see what other scripts are provided by Grails, run grails help from the command line.

You now have a complete working web application, with pages for creating, displaying, editing and listing Car instances. You can launch it with:


$ grails run-app

Grails runs on port 8080 by default. You can easily run on a different port like this:


$ grails -Dserver.port=9090 run-app

Grails

Figure 1: Create Car

Navigate to http:// localhost:8080/AutoMart and look around. Figure 1 and Figure 2 show a couple of the views Grails gives us 'out of the box.' You can also leave it running while you continue to develop. Just save your changes and refresh your browser. This rapid feedback is one of the strengths of Grails.

Grails_2

Figure 2: Car List

Grails Conventions

In our example the Car.groovy file that Grails created for us was placed in a directory called grails-app/domain. This is one of the many conventions in Grails. Placing source files in certain directories and naming them in certain ways can make magical things happen in a Grails application.

Domain Classes

Placing a Groovy class file in the grails-app/domain directory will turn it into a persistent domain class. Several properties and methods will be added to the class dynamically, and Grails will create a table based on the name of the class, with fields for each property.

Refcards_subscribe

Hot Tip

Be careful about adding methods beginning with 'get' to a domain class. Grails will consider that a property and try to persist it. You can avoid this by not giving the method a return type (ie. def getSomething(){...} )

Controllers

Grails controllers are simple Groovy classes with names ending in 'Controller' and residing in the grails-app/controllers directory. Controllers also receive several methods and properties dynamically. Any closure defined as a property in a Controller will become an action reachable by a URL in the following form: application/controller/action.

Views

For each controller in your application there will be a directory under grails-app/views/ named after the controller class (ie. grails-app/views/car). This directory is where your views (.gsp files) go. When a controller action is completed it will automatically attempt to render a view with the name of the action. So, when you call http://localhost:8080/AutoMart/car/list the list action will execute and render the list.gsp page. You can, of course render specific pages but convention can be a huge time-saver.

Services

A Groovy class with a name ending in 'Service' and residing in the grails-app/services directory becomes a Grails service and has built-in transaction handling and more.

TagLibs

Creating custom tags in Grails is so easy it should be illegal. Just create a Groovy class ending with 'TagLib' and place it in the grails-app/TagLib directory. Then define a closure property and write to the OutputStream called 'out' that is already given to you. You can also use the tag's attributes and body by simply declaring them.


class YourTagLib{
def saySomething = {attrs, body ->
  if (attrs.tone == 'loud')
	out << body().toUpperCase()
  elseif (attrs.tone == 'quiet')
	out << body().toLowerCase()
  else
	out << body()
}
You can use this tag in a .gsp like this:
<g:saySomething tone='loud'>
  I'm shouting now!
</g:saySomething>

You can use this tag in a .gsp like this:


<g:saySomething tone='loud'>
   I'm shouting now!
</g:saySomething>


I'M SHOUTING NOW!

There are no extra classes to create, no interfaces to implement, no TLDs to create. You could probably take up a new hobby with the time you'll save!

Testing

Unit Tests

Grails encourages unit testing by automatically creating stubbed out unit tests when creating artifacts (domain classes, controllers, services, and taglibs), and by including a powerful testing framework based on JUnit.

In Grails 1.1 (and earlier via a plugin), there are several classes inheriting from JUnit's TestCase class. Figure 1 shows these classes.

Grails Test Classes

Figure 3: Grails Test Classes

Here are some of the methods that are available to us in the Grails testing framework.

mockDomain(class, list)- Mocks the domain class and stores instances in the list. Provides the dynamic GORM methods to class.
mockFor(class, loose) '" Returns a mock of the class. loose determines whether mock has loose expectations or strict.
mockForConstraintsTest(class, list) '" Similar to mockDomain but works for domains or command objects and adds a validate method to test constraints.
mockController(controllerClass) '" Mocks a controller, adding the usual dynamic properties and methods.
mockTagLib(tagLibClass) '" Mocks a TagLib, adding the usual dynamic properties and methods.
mockLogging(class, enableDebug) '" Adds a mock logger to the class.

Do main Class Magic

Dynamic methods

Grails adds several methods to our domain classes at runtime. Here are some of the most commonly used domain class methods:

Method Description
get(id) Retrieves an instance by id
getAll([id,id,id...]) Retrieves multiple instances by ids
list() Retrieves all instances
listOrderBy*() Retrieves list of instances sorted by expression
findBy*() Returns first instance matching expression
findAllBy*() Returns all instances matching expression
count() Returns total number of instances
countBy*() Returns count of instances matching expression
save() Attempts to persist instance
validate() Validates an instance based on constraints
delete() Attempts to permanently remove instance
withTransaction Executes a closure within a transaction
withCriteria Executes a hibernate criteria using the CriteriaBuilder
hasErrors Returns true if instance has validation errors

Methods such as countBy*() and findBy*() are synthesized methods, made up of the root method name and a combination of domain class properties and the following comparators:

  • Equal (Implied default comparator)
  • NotEqual
  • LessThan
  • LessThanEquals
  • GreaterThan
  • GreaterThanEquals
  • Like
  • like (case insensitive Like)
  • InList
  • Between
  • IsNull
  • IsNotNull

Up to two properties with optional comparators can be combined with a logical operator for example:


Car.countByMakeAndAgeLessThan('Dodge', 4)
Car.findAllByMakeAndModelInList('Ford', ['Mustang', 'Explorer'])


Pagination and Sorting Parameters

The domain method list() takes four parameters which are used for sorting and pagination. These same parameters can be passed in a Map as the last parameter to the findAllBy* methods.

Parameter Description
max The maximum number of instances to return
offset The position to begin retrieving from
sort Domain property to sort by
order Whether to sort asceding or decending

Example: Car.list(max:10, sort:'year', order:'desc')

Constraint Validation

Either the save() or validate() methods shown above will trigger Grails' powerful data validation. Grails provides 17 built-in constraints plus the validation constraint for custom validation.

Many of these constraints also influence database schema generation; those are in shown in bold.

blank (true/false) allow an empty string value
nullable (true/false) allow nulls
max Maximum value of any type that implements java.lang.Comparable
min Minimum value of any type that implements java.lang.Comparable
size Uses a range to determine the upper and lower limits of a collection or a String
maxSize The maximum size of a collection or String
minSize The minimum size of a collection or String
range Uses a range to determine the limits of a numeric value
scale Rounds value to specified number of decimal places - Does not generate an Error
notEqual No comment
inList Value must be contained in supplied list
Matches Value must match supplied regular expression
Unique (true/false) Verifies uniqueness in database
url (true/false) Must be valid URL
email (true/false) Must be valid email address
creditCard (true/false) Must be valid credit card number
password (true/false) Must be valid password
Validator Takes a closure for custom validation. First parameter is value, second (if supplied) is the instance being validated

Here's an example of how constraints are declared in a domain class:


static constraints = {
   make()
   model()
   year()
   desription()
}

If validation fails during a call to save(), no exception is thrown. The failure is quietly recorded and stored in the instances errors property. To see if a domain class instance has validation errors, use the hasErrors() method in conjuction with the errors property, like so:


if (carInsance.hasErrors()){
   carInstance.errors.allErrors.each{ println it }
}

Relationships

GORM also makes relationships between different domain classes easier. Here we'll show how to implement the basic domain relationships.

One-to-one

one-to-one-figure

Unidirectional one-to-one is the simplest type of relationship. One class has a Reference to another. This is declared by a property of the type of another domain class:


class Car {
   Engine engine
}

A bi-directional one-to-one is the same thing but with each class in the relationship having a reference to the other.


class Driver {
    Car car
}
class Car {
    Driver driver
}

Usually in a situation like this you want to show ownership and have cascading updates based on that ownership. With Grails that just takes single line of code:


class Car{
   Driver driver
   static belongsTo = Driver
}

Now a Car belongs to a Driver and when the Driver is saved the Car will be saved too. If the Driver is deleted then the Car goes with him. Makes sense. belongsTo also works with unidirectional relationships.

One-to-many

one-to-one-figure

Figure 5: One-to-many

To declare a uni-directional one-to-many relationship just include a static hasMany property in the owning class.


class Driver {
   static hasMany = [cars : Car]
}

Now a Driver will have a Collection of Car instances called cars.

To make this bi-directional add a belongsTo property to the many class.


class Car{
Driver driver
   static belongsTo = Driver
}

Many-to-many

many-to-many-figure

Figure 6: Many-to-many

A many-to-many relationship can be declared by adding a hasMany to both classes involved and a belongsTo property to one of them.


class Driver {
   static hasMany = [cars : Car]
}
class Car {
   static hasMany = [drivers : Driver]
   static belongsTo = Driver
}

The three r's of co ntrollers

There are three possible conclusions to a controller action in Grails. You can return map of data or nothing and Grails will attempt to display the .gsp view with the same name as the action. You can also redirect to another url or action. The third way is to render something. This can be a view, a template, JSON, XML or just about anything that can be written to the response.

Redirect Method Parameters
controller Controller to redirect to. If action is not present the default action of the controller will be used.
action Action to redirect to. If controller is not present current controller will be used.
id Id to be passed, as params.id, to the redirect.
url URL to redirect to ('http://grails.org').
uri URI to redirect to ('/car/edit/1').
params A map of parameters to be passed to the redirect.
Render Method Parameters
text Text to rendered to the resonse
view A GSP view. Can include pat
template A template (partial GSP view). Often used with AJAX actions.
model A map containing data to be used by the view or template.
bean A single bean to used as the model for the view or template.
collection A collection of objects to be used as the model for the view or template.
builder Builder object to be used to render markup.
contentType Sets the content type of the response.
encoding Sets the encoding of the response

Services

Grails service classes are powerful and easy to use. Here's a few important things to remember when using services.

Transactions

Grails service classes are transactional by default. If you don't want that behavior, for example, if you are going to handle transactions with the dynamic domain class method withTransaction, you can turn it off with a single line:


class CarService {
   static transactional = false
}

Service Injection

Services can be injected into controllers, domain classes, or other services simply by declaring a property with the same name as the service class type but with the first letter lowercase:


class CarController{
def carService
}

You can also inject Services into plain old groovy objects, but it takes a couple more lines of code. First declare the service in your POGO.


class MyPogo {
  def carService
}

Then when you create an instance of your POGO do this:


import org.codehaus.groovy.grails.commons.ApplicationHolder
def myPogo = new MyPogo()
def ctx = ApplicationHolder.application.mainContext
ctx.autowireCapableBeanFactory.autowireBeanProperties(
   myPogo,
   AutowireCapableBeanFactory.AUTOWIRE_BY_NAME,
   false)


This will tell Spring to inject any Spring beans that are declared in the MyPogo class into the myPogo instance. Since Grails service classes are Spring beans, the carService will be injected.

Services and Scope

Grails services are singletons by default. To change that you just need to declare a static scope variable.


static scope = 'request'

Here are the possible values for scope:

Scope Description
request A new instance is created for each request
session One instance is created for an entire session
flash An instance is created that will exist for this request and the next request
prototype A new instance is created for each objec that it's injected into
flow instance exists for the life of a flow (webflow only)
conversation Instance exists for the life of a flow and all sub-flows (webflow only)

GSP

Along with the ability to easily create custom GSP tags, Grails provides over 50 built-in tags. So many that it can be easy to miss one that could be just what you need. The following table shows some of the tags you don't want to miss:

Logical Tags

if- Conditionaly render GSP portions

Attribute Description
test* Expression to evaluate
env* Name of a Grails environment

<g:if env='development' test='${car.year > 2008}'>
   <p>This car is new.</p>
</g:if>

Else- The logical else tag


Else- The logical else tag
No Attributes


<g:if test='car.make == 'Honda''>
...
</g:if>
<g:else>
   <p>Sir, this car is not a Honda.</p>
</g:else>

Looping Tags

each- iterate over each element of the specified object

Attribute Description
in The object to iterate over
status Variable to stor the iteration index in
var The name of the item

<g:each var='car' in='${cars}'>
   <p>Make: ${car.make}</p>
   <p>Year: ${car.year}</p>
</g:each>

findAll- condtionally iterate over objects in a collection

Attribute Description
in The collection to iterate over
expr A Gpath expression

<h1>2003 Vehicles</h1>
<ul>
<g:findAll in='${cars}' expr='it.year == '2003''>
   <li>${it.make} ${it.model}</li>
</g:findAll>
</ul>

Form Tags

form- HTML Form with an action attribute based on controller/action/id

Attribute Description
action* Action to use in the Form Action
controller* Controller to use in the Form Action
id* ID to use in the Form Action
url* A map containing the action/controller/id

<g:form name='myForm' action='show' id='1'>
...
</g:form>
<g:form name='myOtherForm' url='[action:'list',controller:'car']'>
...
</g:form>


*if not specified, the current controller/action will be used

datePicker- Creates HTML selects for day/month/year/hour/second

Attribute Description
name Name of the date picker field set
value Current value of the date picker
default Default date. if '=none', the default is blank
Precision Date granularity: year, month, day, hour, minute
noSelection Map detailing the key and value to use for the 'no selection made' choice in the selected box
Years List/range of displayed years, in specific order

<g:datePicker name='myDate' value='${new Date()}'
noSelection='['':'-Choose-']'/>
<g:datePicker name='myDate' value='${new Date()}' precision='day'
years='${1930..1970}'/>

checkBox- Creates an HTML checkbox form field

Attribute Description
name Name of the checkBox
value Expression; if evaluates to true, 'checked = true'

<g:checkBox name='Used' value='${true}' />

radio- Creates an HTML radio button

Attribute Description
value value represented by radio button. Displayed as label
name Name of radio button
checked Boolean true/false for checked status

<g:radio name='myGroup' value='2' />

Select- Creates an HTML select

from a list or range to select from
value the current value of the property
optionKey property of the bean to use as the key
optionValue property of the bean to use as the value
noSelection single-entry Map with a default key to return and a default value to display.
valueMessage-Prefix Will be prepended to the option value with a '.' to create a key to lookup the value in the i18n message bundle.

<g:select name='car.year' from='${1903..2009}' value='${year}'
noSelection='['':'-Choose car year-']'/>



hiddenField-

Creates an HTML input of type 'hidden'

name the name of the input field
value the value of the text field

<g:hiddenField name='year' value='${carInstance.year}'/>

actionSubmit- Creates a submit button with the specified value

name Required; the title of the button. if 'action' is not specified, this will be the default action.
action the action to execute

<g:actionSubmit value='Button Label' action='Update'/>

Link Tags

link- Creates an HTML anchor tag based on parameters

action name of action to link to - if not specified, the default action will be used
controller name of the controller to link to '" if not specified, the current controller will be used
id the id to use in the link
params a Map containing request parameters
url a Map containing the controller, action, etc. to use in the link

<g:link controller='car' action='list'>List of Cars</g:link>

createLink- Creates a URL which can be used in anchor tags, etc.

action the action to be used in the link- if not specified the default action will be used
controller the controller to be used in the link '" if not specified the current controller will be used
id the id to be used in the link
url a Map containing the controller, action, id, etc.

<g:createLink controller='car' action='show' id='1'/>
will create
AutoMart/car/show/1
As a method call in a GSP:
<a href='${g.createLink(controller:car, action:show, id:1)}'>View
Car #1</a>
will create
<a href='/AutoMart/car/show/1'>View Car #1</a>

createLinkTo- Creates a link to a static resource

dir the directory in the application to link to
file the name of the file in the application to link to

<g:createLinkTo dir='css' file='main.css' />
creates a link to
/shop/css/main.css

Ajax Tags


In order for the Ajax tags to work properly, you need
to include the javascript tag, specifying the library to
use, in the <head> section of your page. For example:
<head>
   <javascript library='yui' />
</head>

javascript- For inclusion of JavaScript libraries and scripts; also a shorthand for inline JavaScript

library the library to include
src the name of the JavaScript file to import - will look for a file in /web-app/js/
base the full URL to prepend to the library name

<g:javascript src='/sites/all/modules/dzone/assets/refcardz/060/thisisascript.js' />
will import
/web-app/js/thisisascript.js
<g:javascript library='scriptaculous' />
will import necessary JavaScript for the Scriptaculous library
Inline JavaScript:
<g:javascript>alert('hello')</g:javascript>


About The Author

Photo of author Dave Klein

Dave Klein

Dave Klein is a developer with Contegix, a company specializing in delivering managed internet infrastructure based upon Linux, Mac OS X, JEE, and Grails. Dave has worked as a developer, architect, project manager, mentor, and trainer for the past 15 years, and has presented at user groups and national conferences. Dave's Groovy and Grails-related thoughts can be found at http://dave-klein.blogspot.com.

Recommended Book

WPF book

In Grails: A Quick-Start Guide,you'll see how to use Grails by iteratively building an unique,working application. By the time we're done, you'll have built and deployed a real,functioning website.

Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.