modular

  • submit to reddit

Getting Started with Drupal

By Matt Vance

14,178 Downloads · Refcard 59 of 151 (see them all)

Download
FREE PDF


The Essential Drupal Cheat Sheet

Drupal is an open source content management system and framework written in PHP. Drupal is used to power many of today’s high-profile sites, such as Popular Science, Ubuntu and the Electronic Frontier Foundation. This DZone Refcard will provide useful information to help you perform three of the most common roles associated with setting up a new Drupal site: site building, theming, and development. Youll also enjoy these other related Refcardz from our DZone Refcardz library: Essential MySQL and PHP.
HTML Preview
Getting Started with Drupal

Getting Started with Drupal

By Matt Vance

about drupal

Drupal is an open source content management system and content management framework written in PHP. Drupal is used to power a variety of high-profile web sites, including sites for Popular Science (http://www.popsci.com/), Ubuntu (http://www.ubuntu.com/), and the Electronic Frontier Foundation (http://www.eff.org/).

Drupal is designed to be modular, with a number of optional modules included in the default “core” Drupal package. These modules serve to extend and enhance the capabilities of Drupal core. In addition, thousands of contributed modules are available for download from the central Drupal community website, Drupal.org.

Drupal is most often run on a LAMP server stack (an acronym for Linux, Apache, MySQL, and PHP). However, Drupal is not limited to a single architecture and can be run under Apple’s OS X or Microsoft Windows. Alternative web servers supported by Drupal include Microsoft IIS and lighttpd. In addition to MySQL, Drupal can also be run using PostgreSQL for database storage.

Hot Tip

For a more thorough PHP reference, see the PHP Refcard (http://refcardz.dzone.com/refcardz/php). Drupal also includes the open source jQuery JavaScript library to simplify the creation of dynamic behavior within a user’s browser. For help using jQuery, check out the jQuery Selectors Refcard. (http://refcardz.dzone.com/refcardz/jquery-selectors).

This Drupal Refcard will provide useful information to help you perform three of the common roles associated with setting up a new Drupal site: site building, theming, and development. This Refcard focuses on Drupal 6, the latest major release available as of this writing.

Drupal site building

Drupal can be used to create just about any type of website, from simple single-author blogs to multi-user social networking communities. Along with Drupal’s flexibility comes a steep learning curve. First time site builders can quickly become overwhelmed by the thousands of available contributed modules.

While the Drupal community strives to work together to create user friendly modules that combine together well, not all modules are created equal. Since developers can’t be expected to test their modules in combination with every other available module, there are bound to be incompatibilities. It is important, especially for first time site builders, to evaluate modules on a test site before installing them on a production site.

Not all Drupal modules are ready for prime time, but some modules have been around long enough and are useful for enough applications to warrant being on a site builder’s short list.

Hot Tip

Sign up for an account on Drupal.org. Some areas and tools on the site are only available to logged in users, plus it is an important first step toward getting involved in the “community” that develops, supports, and steers the Drupal project. Get involved on the forums; both asking and answering questions can help you get up-to-speed more quickly.

CCK

The Content Construction Kit module, also known as CCK (http://drupal.org/project/cck), allows site builders to extend beyond the default content types that are included with Drupal. Not only can the default page and story content types (sometimes called “node” types) be rearranged or customized with additional fields, but completely new content types can also be created. CCK includes several sub-modules for adding a variety of custom field types such as select boxes, check boxes, text boxes, and more. In addition, other contributed modules, such as Date (http://drupal.org/project/date), FileField (http://drupal.org/project/filefield), and ImageField

refcardzad

(http://drupal.org/project/imagefield), can be downloaded separately to add more complex fields to your custom content types.

Views

The Views module (http://drupal.org/project/views) allows site builders a great deal of control and flexibility in presenting lists of content, also called “views”, on a site. The Views module provides a graphical user interface that can output nodes, users, comments, and more. Views can be presented as pages, as RSS feeds, or “blocks” (the often small pieces of content that are typically reused on various pages in sidebars, headers, and footers). The individual items that make up a view can be customized in terms of sort order, fields displayed, and the format of the list (such as unordered lists or tables).

Views Module

The Views module interface can take some time to master, but it is worth the investment. The flexibility of Views can be useful not just to site builders but also to developers, since views can be exported and bundled with modules.

Add on modules such as the Views Bonus Pack (http://drupal.org/project/view_bonus) can extend the Views module even more to present content as CSV files, Microsoft Word DOC files, or as XML.

Hot Tip

When installing new contributed modules and themes, resist the temptation to place the files in the default /modules or /themes directories. To make future upgrades of Drupal easier, create a /sites/all/ modules and /sites/all/themes directory instead. Contributed and custom modules and themes should then be placed in their own respective subdirectories.

Administration menu

The Administration Menu module (http://drupal.org/project/admin_menu) provides administrators with a small drop-down menu at the top of every page to allow easy access to the various administration pages that must be configured when building a new Drupal site.

Pathauto

The Pathauto module (http://drupal.org/project/pathauto) extends Drupal’s core Path module by automating the process of creating more user friendly and search engine friendly URL aliases for a site’s content. Pathauto requires and works in conjunction with the Token module (http://drupal.org/project/token).

Wysiwyg API

Drupal does not include a WYSIWIG editor by default; however, a wide variety of WYSIWYG and other client-side editors can be made to work with Drupal. The WYSIWYG API module (http://drupal.org/project/wysiwyg) provides Drupal integration for a variety of add-on editors, including: TinyMCE, FCKeditor, the YUI Rich Text Editor. Other modules provide support for individual editors, but it is likely that more will opt to integrate with the WYSIWYG API module going forward, in order to avoid duplicating development effort.

Hot Tip

With thousands of contributed modules, there is inevitably overlap in the functionality provided by some modules. Rather than installing each overlapping module to compare functionality, first check the “Comparisons of contributed modules” section of the Drupal handbooks (http://drupal.org/node/266179) to see if someone else has already documented their comparison. Example comparisons include WYSIWYG modules, node access modules, and content rotator modules.

Drupal theming

Drupal provides a flexible theming layer to allow a site’s design to be highly customized. While Drupal can be used in conjunction with a variety of “theme engines” such as Smarty or PHPTAL, most users will want to become familiar with Drupal’s default theme engine format, PHPTemplate.

Depending on the needs of your site, you may choose to create a completely custom theme or use one of Drupal’s “starter themes” as the basis for a new site design. Starter themes such as Zen, Blueprint, or Framework strive to provide a basic foundation that can be customized to provide the look and feel your site requires.

To create your own custom theme from scratch, start by creating a new directory for the theme under the /sites/all/ themes directory. For example, to create a new theme called “Beautiful”, start by creating a new /sites/all/themes/beautiful directory.

Hot Tip

Drupal’s default theme, Garland, was not designed to be a “starter theme.” When looking to transform an existing theme to match a specific design, avoid using Garland. Instead, start from scratch or look to themes such as Zen, Framework, or Basic. For a detailed comparison of starter themes, see http://adaptivethemes.com/starter-themecomparison. html

.info file

Typically a theme directory contains a number of files that work together to make up the theme. At the very least, a [themename] .info file is required in order for Drupal to recognize a theme. Building on the example above, a minimal beautiful.info file might start with the following:


name = Beautiful
description = A example theme created for educational purposes.
core = 6.x
engine = phptemplate

A number of optional keys such as regions, stylesheets, and scripts can also be defined in order to override the defaults Drupal provides. More details can be found in the Drupal handbooks(http://drupal.org/node/171205).

Drupal themes typically contain a number of template files such as page.tpl.php or node.tpl.php. Each template file specifies how a particular portion of the site is to be presented. The various core modules provide default template files that can be copied into your theme directory and edited to customize them to suit the needs of a particular site.

Template files (.tpl.php)

The base template file found in most themes is the page.tpl. php file which acts as a wrapper around most of the other template files. When building a new theme, the default page. tpl.php theme file found in the /modules/system directory can provide a good starting point. You can copy that file into your theme’s directory and customize it as needed.

Hot Tip

Drupal uses a theme registry to cache information about a theme. In order for Drupal to recognize changes to a theme such as adding files or changing the .info file, it is important to clear the theme registry. To clear the theme registry, go to the Performance page (Administer > Site configuration > Performance) and click on the “Clear cached data” button.

Additional template files can be used to customize the presentation of the various smaller elements of a Drupal site such as blocks, comments, polls, and more.

Template file Purpose
page.tpl.php the main container template file, which acts as a wrapper for the other template files below; see the following page for a list of available variables within the page.tpl.php file: http://api.drupal.org/api/file/modules/system/page.tpl.php
page-front.tpl.php can be used to specify a custom front page
node.tpl.php controls how the various content types or “nodes” are displayed; see the following page for a list of available variables within the node.tpl.php file: http://api.drupal.org/api/file/modules/node/node.tpl.php/6
node-[nodetype].tpl.php optional template files used to target and customize nodes of a specific content type
block.tpl.php contains the code used to display reuseable “block” content that may appear in multiple places within a site
block-[region].tpl.php optional template files to customize how blocks in specific block “regions” will appear; regions are the areas specified in the theme’s .info file where blocks can be designated to appear (such as headers, sidebars, etc)
comment.tpl.php controls the formatting of user comments

Template files can be targeted to customize specific content of a site by naming the files according to specific “suggestions.” For example, to customize the front page of a site, create a copy of the page.tpl.php file named page-front.tpl.php and customize the new front page template as needed. See the Drupal handbooks (http://drupal.org/node/190815) for more details about the various core template files and how to use and customize the suggestion options.

Hot Tip

When creating your own theme from scratch, be sure to output the $closure variable, just before the closing tag in the page.tpl.php file. The $closure variable is easy to overlook, but it is important because it outputs some final markup, which may cause some modules to fail, if it is missing.

template.php

The template.php file is an optional file used as a container for conditional processing and overriding of theme functions. In addition to overriding theme output using the template file method outlined above, Drupal also allows theme functions (any function beginning with “theme_”) to be overridden inside the template.php file. Those more familiar with programming in PHP may prefer to use template functions to override Drupal’s defaults in order to gain more flexibility and performance. A list of Drupal’s default theme functions can be found on the Drupal API site
(http://drupal.org/api/group/themeable).

Hot Tip

For help tracking down the particular function that controls the content you want to customize, install the Devel module (http://drupal.org/project/devel) and enable the Theme developer module that comes with it. The Theme developer module provides a graphical tool that can be used to select specific portions of a page and display the theme function or template file responsible for generating it.

style.css

Drupal will automatically recognize a style.css file as a theme’s primary cascading style sheet file. Additional CSS files can be specified in the .info file using the “stylesheets” key.

screenshot.png

The screenshot.png file is a thumbnail sized image of the theme presented on Drupal’s theme administration page to provide users with a preview of how a theme will look.

Drupal development

Drupal has a reputation as being created by developers for developers. While it has made great strides recently at becoming more user friendly, Drupal still has a lot to offer developers. Drupal has been designed with flexibility in mind. Developers can customize the vast majority of Drupal’s functionality through Drupal’s system of hook functions.

Novice users should not be dissuaded from creating their own custom modules. Even a simple single-function module can be useful for things such as customizing how Drupal presents a particular piece of content or form.

Hot Tip

Resist the temptation to modify the core of Drupal. “Hacking core” is discouraged, in favor of creating modules that modify Drupal’s behavior instead. Creating modules avoids having to maintain and apply patches to Drupal as updates get released
.

To develop a new custom module, start by creating a new directory for the module under the /sites/all/modules directory. For example, to create a new module called “Functional”, start by creating a new /sites/all/modules/functional directory.

Hot Tip

Before sitting down to develop a new custom module, take the time to browse or search the contributed modules available on Drupal.org. The thousands of modules available there are typically developed to be reusable in a variety of environments. You may not find a module that does exactly what you are looking for, you may find one that can be adapted to suit your needs. If you make improvements to an existing module, consider contributing your code back in the module’s issue queue, in the form of a patch. In addition to helping others, if the patch gets accepted, it will make future upgrades of the module on your own site easier.

.info file

As with themes, each Drupal module must include at least a .info file in order to be recognized. An example functional.info file might consist of the following:


; $Id$
name = Functional module
description = “A simple example module created for educational
purposes.”
core = 6.x

See the Drupal handbooks (http://drupal.org/node/231036) for details on the other keys that can be specified in the module’s .info file.

Once the .info file has been created, a module can be enabled on the Module administration page (Site building > Modules). However, until the .module file has been created, the module won’t provide any new functionality.

.module file

The .module file typically contains the majority of the code for a module. Modules interact with the core of Drupal by implementing various hook functions that get called as Drupal carries out various tasks. Certain specific hook functions will need to be implemented depending on what functionality or customization a particular module needs to provide. A list of available hook functions can be found on the Drupal API Reference site (http://api.drupal.org/api/group/hooks).

For our example functional.module file, we will implement the hook_nodeapi function. By implementing hook_nodeapi, a module can act on the node object used as a container for the majority of content within Drupal.

To implement a particular hook function within a module, replace the word hook within the functions name with the name of the module. For example, in a module called functional, the hook_nodeapi function is implemented as functional_nodeapi:


<?php
  function functional_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
   switch ($op) {
    case ‘view’:
     $node->content[‘body’][‘#value’] .= “<br><br>Brought to you
by RefCardz”;
     break;
  }
}

Once the “functional” module is enabled, all nodes within the site will appear with a “Brought to you by RefCardz” notice at the bottom.

Hot Tip

To quickly dump variables to the screen for debugging purposes, you can take advantage of the message area typically found at the top of the page in most themes, by using the following function: drupal_set_message(‘<pre>’ . print_r($variable, TRUE) . ‘</pre>’);
If you have the Devel module enabled, you can take advantage of more cleanly formatted output by using the following instead: dpm($variable);

By implementing hook_form_alter, modules can use Drupal’s Form API to add, remove, or change forms. For example, some sites use the Views module or Panels module to customize the site’s front page, so the “Promoted to front page” publishing option may need to be removed to avoid confusion. The following code will remove the checkbox used to promote content to the front page.


function functional_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == ‘page_node_form’) {
    unset($form[‘options’][‘promote’]);
  }
}

For a more detailed introduction to the Forms API, see the “Forms API Quickstart Guide” (http://api.drupal.org/api/file/ developer/topics/forums_api.html)

Useful Hook Functions (for a complete listing of hook functions, see
http://api.drupal.org/api/group/hooks/)
Description
hook_block
http://api.drupal.org/api/function/hook_block/
Declare a block or set of blocks
hook_cron
http://api.drupal.org/api/function/hook_cron/
Perform periodic actions
hook_db_rewrite_sql
http://api.drupal.org/api/function/hook_db_rewrite_sql/
Rewrite database queries, usually for access control
hook_enable
http://api.drupal.org/api/function/hook_enable/
Perform necessary actions after module is enabled
hook_form_alter
http://api.drupal.org/api/function/hook_form_alter/
Perform alterations before a form is rendered
hook_mail_alter
http://api.drupal.org/api/function/hook_mail_alter/
Alter any aspect of the emails sent by Drupal
hook_mail
http://api.drupal.org/api/function/hook_mail/
Prepare an email message based on parameters
hook_menu
http://api.drupal.org/api/function/hook_menu/
Define menu items and page callbacks
hook_perm
http://api.drupal.org/api/function/hook_perm/
Define user permissions
hook_user
http://api.drupal.org/api/function/hook_user/
Act on user account actions
hook_watchdog
http://api.drupal.org/api/function/hook_watchdog/
Log an event message

.install file

Another file commonly found in Drupal modules is the .install file. The .install file is used to store code that is run when a module is installed or uninstalled, such as the hook_schema and hook_install functions.

Common .install File Functions Description
hook_install
http://api.drupal.org/api/function/hook_install/
Install the current version of the database schema, and any other setup tasks.
hook_schema
http://api.drupal.org/api/function/hook_schema/
Define the current version of the atabase schema.
hook_uninstall
http://api.drupal.org/api/function/hook_uninstall
Remove any tables or variables that the module sets.

Modules for developers

Modules for Developers

Several of the contributed modules for Drupal provide tools useful to module developers.

Deadwood

As new versions of Drupal get released, it can take a while for existing modules to get upgraded. The Deadwood module (http://drupal.org/project/deadwood) helps speed up the process of upgrading Drupal modules by automating some of the code updates.

Devel module

The Devel module (http://drupal.org/project/devel) provides tools for clearing Drupal’s cache, for generating dummy content, for debugging access issues, for performance logging, and much more.

Devel Mode

The Devel module also includes an open source debugging tool called Krumo that can display a structured representation of any PHP variable. Devel adds “Dev load” and “Dev render” tabs to nodes which output the Node object through Krumo. With Devel enabled, you can output your own variables through Krumo using Devel’s print message function, dpm().

Coder module

Since the Deadwood module doesn’t completely automate the process of upgrading modules from one version of Drupal to the next, there is usually some manual coding to be performed after running Deadwood. That is where the Coder module (http://drupal.org/project/coder) comes in handy. The Coder module does not modify code, but it provides an automated code review that can pinpoint areas of code that need to be updated.

Coder Module

The Coder module can also help enforce coding standards by pinpointing sloppy coding and suggesting ways to clean it up. The Coder module can be especially helpful to run before contributing code back to the community at Drupal.org. Schema

The Schema module (http://drupal.org/project/schema)

provides tools for working with Drupal’s database Schema API. If you’ve already manually created the tables required by a module, the schema module can provide the corresponding schema data structure to be added to your module’s .install file, making it easier to replicate the same tables on another Drupal installation.

Cache Disable

Drupal’s caching system can be a source of confusion and productivity loss, if you are not careful. Rather than having to remember each of the various tasks that require the cache to be flushed, install and enable the Cache Disable module (http://drupal.org/project/cache_disable) when doing development on a new site. Just remember to turn the module off, once you have completed your development work.

API

The API module (http://drupal.org/project/api) is used to generate the hyperlinked documentation found at api.drupal. org. The same module can be used to provide a local version of Drupal’s API documentation. In addition to providing documentation on Drupal’s core modules, the API module can also generate documentation pages for installed modules that follow Drupal’s coding standards. If you prefer not to set up your own API site, you can still browse the documentation for many of the contributed modules, courtesy of Drupal consulting company Lullabot (http://api.lullabot.com/)

Other API Modules

Though Drupal does provide a full-fledged development framework, it doesn’t include everything one might need for every possible coding task. Thankfully, the repository of contibuted modules on drupal.org includes quite a few API modules. Many of the API modules provide no functionality on their own, but provide API code that other modules and module developers can build on. Example API modules include the Voting API (http://drupal.org/project/feedapi), Chart API (http://drupal.org/project/chart), and the Import/ Export API (http://drupal.org/project/importexportapi).

Resources

URL Reference
http://api.drupal.org/ Documentation of Drupal’s API
http://drupal.org/handbooks The Drupal community maintains several handbooks including documentation for beginners, themers, and developers
http://drupalcodesearch.com/ Drupal Code Search allows users to search much of Drupal’s contributed code, though the index may not reflect the latest up-to-the-minute changes
http://cvs.drupal.org/ A web interface to browse the code in the Drupal.org CVS repository, from the start of the project to the latest in contributed modules
http://drupalmodules.com/ Drupal Modules allows users to rate modules. Ratings can be handy when choosing modules to use on a site
http://drupal.org/planet Drupal Planet aggregates a number of blogs that post regularly about Drupal
http://groups.drupal.org/ Groups.Drupal is a gathering place for niche groups within the Drupal community. Try searching for a user group near you or a group focused on your specific area of interest
http://drupal.org/irc Learn how to connect to Drupals IRC channels and connect with a world-wide community of developers at all hours of the day
http://drupal.org/mailing-list Drupal.org provides a number of mailing lists to keep the community up-to-date. Anyone running a public Drupal site should subscribe to the security announcements mailing list
http://association.drupal.org/ The Drupal Association is a not-for-profit association charged with providing support to the Drupal project
http://drupal.org/getting-involved The Drupal project thrives largely due to a strong community of contributors. Read the “Getting Involved” handbook to learn how you too can contribute
http://ww.lullabot.com/podcast Several Drupal podcasts exist, both in audio and video formats, but the Lullabot podcasts are longest-running and arguably the most in-depth

About The Author

Photo of Matt Vance

Matt Vance

is a Web developer, technology consultant, and freelance writer living in Austin, Texas. He has written for Macworld magazine and Lifehacker.com. He can be contacted through his website, http://minezone.org/

Recommended Book

Drupal

Newcomers will find a thorough introduction to the framework, while experienced Drupal developers will learn best practices for building powerful websites. With Using Drupal, you’ll find concrete and creative solutions for developing the exact community website you have in mind.


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 Spring-DM

By Craig Walls

16,699 Downloads · Refcard 57 of 151 (see them all)

Download
FREE PDF


The Essential Spring-DM Cheat Sheet

Spring is a framework that promotes development of loosely coupled/highly cohesive objects through dependency injection and interface-oriented design. Spring Dynamic Modules (Spring-DM) brings Spring and OSGi together to enable a declarative service model for OSGi that leverages Spring’s power of dependency injection. This DZone Refcard shows you how to use Spring-DM to wire together OSGi services to build highly modular and dynamic applications. You may also enjoy the other Spring DZone Refcardz in our Collection: Spring Configuration and Spring Annotations.
HTML Preview
Getting Started with Spring-DM

Getting Started with Spring-DM

By Craig Walls

about spring-dm

Spring is a framework that promotes development of looselycoupled/ highly-cohesive objects through dependency injection and interface-oriented design. OSGi is a framework specification that promotes development of loosely-coupled/ highly-cohesive application modules through services and interface-oriented design. Seems like a match made in heaven! Spring Dynamic Modules (Spring-DM) brings Spring and OSGi together to enable a declarative service model for OSGi that leverages Spring’s power of dependency injection. This reference card will be your resource for working with Spring- DM to wire together OSGi services and ultimately building modular applications.

You may be interested to know that Spring-DM is the basis for the SpringSource dm Server, a next-generation application server that embraces modularity through OSGi. What’s more, the upcoming OSGi R4.2 specification includes a component model known as the OSGi Blueprint Services that is heavily influenced by Spring-DM.

Introducing Spring-DM

The star player of Spring-DM is a bundle known as the Spring- DM extender. The Spring-DM extender watches for bundles to be installed and inspects them to see if they are Springenabled (that is, if they contain a Spring application context definition file). When it finds a Spring-enabled bundle, the extender will create a Spring application context for the bundle.

Spring Application Contexts

Spring-DM also provides a Spring configuration namespace that enables you to declare and publish Spring beans as OSGi services and to consume OSGi services as if they were just beans in a Spring application context. This declarative model effectively eliminates the need to work with the OSGi API directly.

Installing Spring-DM

One of the nice things about Spring-DM is that you do not need to include it in the classpath of your OSGi bundles or even reference it from those bundles. Installing Spring-DM involves two parts:

  1. Installing the Spring-DM and supporting bundles in your OSGi framework
  2. Adding the Spring-DM configuration namespace to your bundle’s Spring configuration XML files

You can download Spring-DM from
http://www.springframework.org/osgi. The distribution comes complete with everything you need to work with Spring- DM, including the Spring-DM extender bundle and all of its dependency bundles.

Installing the Spring-DM extender bundles

There are several means by which you can install bundles into an OSGi framework, depending on the OSGi framework and any add-ons or tools you may be using. But the most basic way is to use the “install” command that is available in most OSGi framework shells. For example, to install the Spring- DM extender bundle and the supporting Spring-DM bundles (assuming that you’ve unzipped the Spring-DM distribution in / spring-dm-1.2.0):


osgi> install file:///spring-dm-1.2.0/dist/spring-osgi-core-
   1.2.0.jar
osgi> install file:///spring-dm-1.2.0/dist/spring-osgi-extender-
   1.2.0.jar
osgi> install file:///spring-dm-1.2.0/dist/spring-osgi-io-
   1.2.0.jar

Spring-DM depends on the Spring framework, so you’ll also need to install several other Spring bundles:

refcardzad


osgi> install file:///spring-dm-1.2.0/lib/spring-aop-2.5.6.A.jar
osgi> install file:///spring-dm-1.2.0/lib/spring-context-
    2.5.6.A.jar
osgi> install file:///spring-dm-1.2.0/lib/spring-core-2.5.6.A.jar
osgi> install file:///spring-dm-1.2.0/lib/spring-beans-2.5.6.A.jar

Finally, you’ll also need to install several other supporting bundles that Spring and Spring-DM depend on:


osgi> install file:///spring-dm-1.2.0/lib/com.springsource.net.
   sf.cglib-2.1.3.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.org.
   aopalliance-1.0.0.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.slf4j.
   api-1.5.0.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.slf4j.
   log4j-1.5.0.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.slf4j.
   org.apache.commons.logging-1.5.0.jar
osgi> install file:///spring-dm-1.2.0/lib/log4j.osgi-1.2.15-
   SNAPSHOT.jar

Hot Tip

Use tools to help install bundles Installing bundles using the “install” command should work with almost any OSGi framework, but it is also quite a manual process. Pax Runner (http:// paxrunner.ops4j.org) is an OSGi framework launcher that takes a lot of the tedium out of installing bundles. Just use Pax Runner’s “spring dm” profile: % pax-run.sh --profiles=spring.dm

The Spring-DM configuration namespace

Schema URI:

http://www.springframework.org/schema/osgi

Schema XSD:

http://www.springframework.org/schema/osgi/spring-osgi.xsd

When it comes to declaring services and service consumers in Spring-DM, you’ll use Spring-DM’s core namespace. To do that, you’ll need to include the namespace in the XML file.


<?xml version=”1.0” encoding=”UTF-8”?>
<beans xmlns=”http://www.springframework.org/schema/beans”
	xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
	xmlns:osgi=”http://www.springframework.org/schema/osgi”
	xsi:schemaLocation=”http://www.springframework.org/
schema/beans
	    http://www.springframework.org/schema/beans/
spring-beans.xsd
		   http://www.springframework.org/schema/osgi
		     http://www.springframework.org/schema/
osgi/spring-osgi.xsd”>
...
</beans>

Spring’s “beans” namespace is the default namespace, but if you know that most or all of the elements in the Spring configuration file will be from the Spring-DM namespace, you can make it the default namespace:

spring beans

Publishing Services

To demonstrate Spring-DM’s capabilities, we’re going to create a few OSGi services that translate English text into some other language. All of these services will implement the following Translator interface:


package com.habuma.translator;
public interface Translator
   {
String translate(String text);
}

The first service we’ll work with is one that translates English into Pig Latin. It’s implementation looks something like this:


package com.habuma.translator.piglatin;
import com.habuma.translator.Translator;
public class PigLatinTranslator implements Translator {
	private final String VOWELS = “AEIOUaeiou”;
	public String translate(String text) {
	  // actual implementation left out for brevity
	}
}

If we were working with basic OSGi (that is, without Spring- DM), we’d publish this service to the OSGi service registry using the OSGi API, perhaps in a bundle activator’s start() method:


public void start(BundleContext context) throws Exception {
	context.registerService(Translator.class.getName(),
				new PigLatinTranslator(), null);
}

Although the native OSGi approach will work fine, it requires us to work programmatically with the OSGi API. Instead, we’ll publish services declaratively using Spring-DM. The first step: Create a Spring context definition file that declares the PigLatinTranslator as a Spring bean:


<?xml version=”1.0” encoding=”UTF-8”?>
<beans xmlns=”http://www.springframework.org/schema/beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
		xsi:schemaLocation=”http://www.springframework.org/
schema/beans
		  http://www.springframework.org/schema/beans/springbeans.
xsd”>
  <bean id=”pigLatinTranslator”
    class=”com.habuma.translator.piglatin.PigLatinTranslator” />
</beans>

Hot Tip

Overriding the context configuration location By default, the Spring-DM extender looks for all XML files located in a bundle’s META-INF/spring folder and assumes that they’re all Spring context definition files that are to be used to create a Spring application context for the bundle; however, if you’d like to put your context definition files elsewhere in the bundle, use the Spring-Context: header in the META-INF/ MANIFEST.MF file.
For example, if you’d rather place your Spring configuration files in a directory called “spring-config” at the root of the bundle, add the following entry to your bundle’s manifest: Spring-Context: spring-config/*.xml

This Spring context file can be named anything, but it should be placed in the Pig Latin translator bundle’s META-INF/ spring directory. When the bundle is started in an OSGi framework, the Spring-DM extender will look for Spring context configuration files in that directory and use them to create a Spring application context for the bundle.

Publishing a simple OSGi service

By itself the Spring context we’ve created only creates a bean in the Spring application context. It’s not yet an OSGi service. To publish it as an OSGi service, we’ll create another Spring context definition file that uses the Spring-DM namespace:


<<?xml version=”1.0” encoding=”UTF-8”?>
<<beans:beans xmlns:beans=”http://www.springframework.org/schema/
beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
		xmlns=”http://www.springframework.org/schema/osgi”
		xsi:schemaLocation=”http://www.springframework.org/
schema/beans
			http://www.springframework.org/schema/beans/
spring-beans.xsd
			  http://www.springframework.org/schema/osgi
				http://www.springframework.org/schema/
osgi/spring-osgi.xsd”>
   <<service ref=”pigLatinTranslator”
	  interface=”com.habuma.translator.Translator” />
<</beans:beans>

Hot Tip

Don’t mix your Spring and OSGi contexts Although you can certainly define all of your bundle’s Spring beans and OSGi services in a single Spring context definition file, it’s best to keep them in separate files (all in META-INF/spring). By keeping the OSGi-specific declarations out of the normal Spring context definition, you’ll be able to use the OSGi-free context to do non-OSGi integration tests of your beans.

This new Spring context file uses Spring-DM’s element to publish the bean whose ID is “pigLatinTranslator” in the OSGi service registry. The ref attribute refers to the Spring bean in the other context definition file. The interface attribute identifies the interface under which the service will be available in the OSGi service registry.

Publishing a service under multiple interfaces

Let’s suppose that the PigLatinTranslator class were to implement another interface, perhaps one called TextProcessor. And let’s say that we want to publish the service under both the Translator interface and the TextProcessor interface. In that case, you can use the element to identify the interfaces for the service:


<service ref=”pigLatinTranslator”>
  <interfaces>
    <beans:value>com.habuma.translator.Translator</beans:value>
    <beans:value>com.habuma.text.TextProcessor</beans:value>
  </interfaces>
</service>

Auto-selecting service interfaces

Instead of explicitly specifying the interfaces for a service, you can also let Spring-DM figure out which interfaces to use by specifying the auto-export attribute:


<service ref=”pigLatinTranslator”
       auto-export=”interfaces” />

By setting auto-export to “interfaces”, it tells Spring-DM to publish the service under all interfaces that the implementation class implements. You can also set auto-export to “all-classes” to publish the service under all interfaces and classes for the service or “class-hierarchy.”

Publishing a service with properties

It’s also possible to publish a service with properties to qualify that service. These properties can later be used to help refine the selection of services available to a consumer. For example, let’s say that we want to qualify Translator services by the language that they translate to:


<rvice ref=”pigLatinTranslator”
      interface=”com.habuma.translator.Translator”>
<service-properties>
   <beans:entry key=”translator.language” value=”Pig Latin” />
 </service-properties>
</service>

The <service-properties> element can contain one or more <entry> elements from the “beans” namespace. In this case, we’ve added a property named “translator.language” with a value of “Pig Latin”. Later, we’ll use this property to help select this particular service from among a selection of services that all implement Translator.

Consuming Services

Now that we’ve seen how to publish a service in the OSGi service registry, let’s look at how we can use Spring-DM to consume that service. To get started, we’ll create a simple client class:


package com.habuma.translator.client;
import java.util.List;
import com.habuma.translator.Translator;
public class TranslatorClient {
  private static String TEXT = “Be very very quiet. I’m hunting
rabbits!”;
  public void go() {
     System.out.println(“ TRANSLATED: “ +
        translator.translate(TEXT));
  }
  private Translator translator;
  public void setTranslator(Translator translator) {
    this.translator = translator;
  }
}

TranslatorClient is a simple POJO that is injected with a Translator and uses that Translator in its go() method to translate some text. We’ll declare it as a Spring bean like this:


<?xml version=”1.0” encoding=”UTF-8”?>
		<beans xmlns=”http://www.springframework.org/schema/beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/
schema/beans
			http://www.springframework.org/schema/beans/springbeans.
xsd”>
  <bean class=”com.habuma.translator.client.TranslatorClient”
     init-method=”go”>
   <property name=”translator” ref=”translator” />
  </bean>
</beans>

As with the service’s Spring context declaration, the name of this Spring context definition can be named anything, but it should be placed in the client bundle’s META-INF/spring folder so that the Spring-DM extender will find it.

The bean is declared with the init-method attribute set to call the go() method when the bean is created. And we use the <property> element to inject the bean’s translator property with a reference to a bean whose ID is “translator”.

The big question here is: Where does the “translator” bean come from?

Simple service consumption

Spring-DM’s <reference> element mirrors the <service> element. Rather than publishing a service, however, <reference> retrieves a service from the OSGi service registry. The simplest way to consume a Translator service is as follows:


<reference id=”translator”
interface=”com.habuma.translator.Translator” />

When the Spring-DM extender creates a Spring context for the client bundle, it will create a bean with an ID of “translator” that is a proxy to the service it finds in the service registry. With that id attribute and interface, it is quite suitable for wiring into the client bean’s translator property.

Setting a service timeout

In a dynamic environment like OSGi, services can come and go. When the client bundle starts up, there may not be a Translator service available for consumption. If it’s not available, then Spring-DM will wait up to 5 minutes for the service to become available before giving up and throwing an exception.

But it’s possible to override the default timeout using the <reference> element’s timeout attribute. For example, to set the timeout to 1 minute instead of 5 minutes:


<reference id=”translator”
	interface=”com.habuma.translator.Translator”
	timeout=”60000” />

Notice that the timeout attribute is specified in milliseconds, so 60000 indicates 60 seconds or 1 minute.

Optional service references

Another way to deal with the dynamic nature of OSGi services is to specify that a service reference is optional. By default, the cardinality of a reference to a service is “1..1”, meaning that the service must be found within the timeout period or else an exception will be thrown. But you can specify an optional reference by setting the cardinality to “0..1”:


<reference id=”translator”
	interface=”com.habuma.translator.Translator”
	cardinality=”0..1” />

Filtering services

Imagine that we have two or more Translator services published in the OSGi service registry. Let’s say that in addition to the Pig Latin translator there’s also another Translator service that translates text into Elmer Fudd speak. How can we ensure that our client gets the Pig Latin service when another implementations may be available?

Earlier, we saw how to set a property on a service when it’s published. Now we’ll use that property to filter the selection of services found on the consumer side:


<reference id=”translator”
	interface=”com.habuma.translator.Translator”
	filter=”(translator.language=Pig Latin)” />

The filter attribute lets us specify properties that will help refine the selection of matching services. In this case, we’re only interested in a service that has its “translator.language” property set to “Pig Latin”.

Consuming multiple services

But why choose? What if we wanted to consume all matching services? Instead of pin-pointing a specific service, we can use Spring-DM’s <list> element to consume a collection of matching services:


<list id=”translators”
	interface=”com.habuma.translator.Translator” />

The Spring-DM extender will create a list of matching services that can be injected into a client bean collection property such as this one:


private List<Translator> translators;
public void setTranslators(List<Translator> translators) {
  this.translators = translators;
}

Optionally, you can use Spring-DM’s <set> element to create a set of matching services:


<set id=”translators”
   interface=”com.habuma.translator.Translator” />

The <list> and <set> elements share many of the same attributes with <reference>. For example, to consume a set of all Translator services filtered by a specific property:


<set id=”translators”
interface=”com.habuma.translator.Translator”
filter=”(translator.language=Elmer Fudd)” />

Testing Bundles

Hopefully, you’re in the habit of writing unit tests for your code. If so, that practice should extend to the code that is contained within your OSGi bundles. Because Spring-DM encourages POJO-based OSGi development, you can continue to write unit-tests for the classes that define and consume OSGi services just like you would for any other non-OSGi code.

But it’s also important to write tests that exercise your OSGi services as they’ll be used when deployed in an OSGi container. To accommodate in-OSGi integration testing of bundles, Spring-DM provides AbstractConfigurableBundleCreatorTests, a JUnit 3 base test class from which you can write your bundle tests.

What’s fascinating is how tests based on AbstractConfigurableBundleCreatorTests work. When the test is run, it starts up an OSGi framework implementation (Equinox by default) and installs one or more bundles into the framework. Finally, it wraps itself in an on-the-fly bundle and installs itself into the OSGi framework so that it can test bundles as an insider.

Writing a basic OSGi test

To illustrate, let’s write a simple test that loads our Translator interface bundle and the Pig Latin implementation bundle:


package com.habuma.translator.test;
import org.osgi.framework.ServiceReference;
import org.springframework.osgi.test.
AbstractConfigurableBundleCreatorTests;


import com.habuma.translator.Translator;
public class PigLatinTranslatorBundleTest
      extends AbstractConfigurableBundleCreatorTests {
  @Override
  protected String[] getTestBundlesNames() {
     return new String[] {
		“com.habuma.translator, interface, 1.0.0”,
		“com.habuma.translator, pig-latin, 1.0.0”
      };
  }
  public void testOsgiPlatformStarts() {
    assertNotNull(bundleContext);
  }
}

The getTestBundleNames() method returns an array of Strings where each entry represents a bundle that should be installed into the OSGi framework for the test. The format of each entry is a comma-separated set of values that identify the bundle by its Maven group ID, artifact ID, and version number.

So far, our test has a single test method, testOsgiPlatformStarts(). All this method does is test that the OSGi framework has started by asserting that bundleContext (inherited from AbstractConfigurableBundleCreatorTests) is not null.

Testing OSGi service references

A more interesting test we could write is one that uses the bundle context to lookup a reference to the Translator service and assert that it meets our expectations:


public void testServiceReferenceExists() {
  ServiceReference serviceReference =
    bundleContext.getServiceReference(Translator.class.
getName());
	assertNotNull(serviceReference);
	assertEquals(“Pig Latin”,
       serviceReference.getProperty(“translator.language”));
}

Here we retrieve a ServiceReference from the bundle context and assert that it isn’t null. This means that some implementation of the Translator service has been published in the OSGi service registry. Then, it examines the properties of the service reference and asserts that the “translator.language” property has been set to “Pig Latin”, as we’d expect from how we published the service earlier.

Testing OSGi services

One more thing we could test is that the Translator service does what we’d expect it to do. Certainly, this kind of test usually belongs in a unit test. But it’s still good to throw a smoke test its way to make sure that we’re getting the service we’re expecting.

We could use the ServiceReference to lookup the service. But, we can avoid any additional work with the OSGi API by having the Translator service wired directly into our test class. First, let’s add a Translator property and setter method to our test class


private Translator translator;
public void setTranslator(Translator translator) {
  this.translator = translator;
}

When the test is run, Spring will attempt to autowire the property with a bean from its own Spring application context. But we haven’t defined a Spring application context for the test yet. Let’s do that now:


<?xml version=”1.0” encoding=”UTF-8”?>
<beans:beans xmlns:beans=”http://www.springframework.org/schema/
beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
		xmlns=”http://www.springframework.org/schema/osgi”
   xsi:schemaLocation=”http://www.springframework.org/schema/
beans
      http://www.springframework.org/schema/beans/spring-beans.
xsd
    http://www.springframework.org/schema/osgi
    http://www.springframework.org/schema/osgi/spring-osgi.xsd”>
  <reference id=”translator”
    interface=”com.habuma.translator.Translator” />
</beans:beans>

You’ll recognize that this Spring context definition looks a lot like the one we created for the service consumer. In fact, our test class will ultimately be a consumer of the Translator service. We just have one more thing to do before we can test the service—we’ll need to override the getConfigLocations() method to tell the test where it can find the context definition file:


@Override
protected String[] getConfigLocations() {
   return new String[] { “bundle-test-context.xml” };
}

Now we can write our test method:


public void testTranslatorService() {
	assertNotNull(translator);
	assertEquals(“id-DAY is-thAY ork-wAY”,
       translator.translate(“Did this work”));
}

This method assumes that by the time it is invoked, the translator property has been set. It first asserts that it is not null and then throws a simple test String at it to test that the service does what we expect.

Changing the tested OSGi framework

By default, Spring-DM tests are run within Equinox. But you can change them to run within another OSGi framework implementation such as Apache Felix or Knopflerfish by overriding the getConfigLocations() method. For example, to run the test within Apache Felix:


@Override
  protected String getPlatformName() {
    return Platforms.FELIX;
}

Or for Knoplerfish:


@Override
protected String getPlatformName() {
  return Platforms.KNOPFLERFISH;
}

Providing a Custom Manifest

When a Spring-DM test gets wrapped up in an on-the-fly bundle, a manifest will be automatically generated for it. But if you’d like to provide a custom manifest. To provide a custom manifest for the on-the-fly bundle, all you need to do is override the getManifestLocation(). For example:


protected String getManifestLocation() {
  return “classpath:com.habuma.translator.Translator.MF”;
}

Be aware, however, that if you provide a custom manifest, you must include a few things in that manifest to make Spring-DM testing work. First, you’ll need to specify a bundle activator:


Bundle-Activator: org.springframework.osgi.test.JUnitTestActivator

And you’ll need to import JUnit and Spring-DM packages:


Import-Package: junit.framework,
  org.osgi.framework,
  org.apache.commons.logging,
  org.springframework.util,
  org.springframework.osgi.service,
  org.springframework.osgi.util,
  org.springframework.osgi.test,
  org.springframework.context

References

Example Source Code:

http://www.habuma.com/refcard/spring-dm/translator.zip

Spring-DM Homepage:

http://www.springframework.org/osgi

OSGi Alliance:

http://www.osgi.org

Modular Java on Twitter:

http://twitter.com/modularjava

Craig’s Modular Java Blog:

http://www.modularjava.com

Craig’s Spring Blog:

http://www.springinaction.com

56 76

About The Author

Photo of Craig Walls

Craig Walls

is a Texas-based software developer with more than 15 years experience working the telecommunication, financial, retail, education, and software industries. He’s a zealous promoter of the Spring Framework, speaking frequently at local user groups and conferences and writing about Spring and OSGi on his blog. When he’s not slinging code, Craig spends as much time as he can with his wife, two daughters, six birds, and two dogs.

Craig’s Publications:

  • Modular Java: Creating Flexible Applications with OSGi and Spring, 2009
  • Spring in Action, 2nd Edition, 2007
  • XDoclet in Action, 2003

Craig’s Blog: http://www.springinaction.com

Recommended Book

Spring in action

Newcomers will find a thorough introduction to the framework, while experienced Drupal developers will learn best practices for building powerful websites. With Using Drupal, you’ll find concrete and creative solutions for developing the exact community website you have in mind.


Recommended Book

ModularJava

Modular Java is filled with tips and tricks that will make you a more proficient OSGi and Spring-DM developer. Equipped with the know-how gained from this book, you’ll be able to develop applications that are more robust and agile.

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 Drupal? Check out this cheat sheet!

Download our Getting Started with Drupal Refcard now! 

0 replies - 5075 views - 06/23/09 by Lyndsey Clevesy in Announcements

Have you started using Spring Dynamic Modules yet?

Get started now! Download the latest DZone Refcard: Getting Started with Spring-DM. 

0 replies - 5272 views - 06/08/09 by Lyndsey Clevesy in Announcements