Archive for July, 2012

Part VII: ASP.NET MVC Contact Manager with Spring.NET

2

This series is an adaption of my “Getting Started with Dependency Injection using Spring.NET” presentation, which was a session available at the Orlando .NET Code Camp 2012. Since I received invaluable participation and feedback from the attendees, this post will include expanded material and code examples.

This should be the final part of the series, which is the missing ASP.NET MVC example from the Orlando .NET Code Camp presentation. I received several requests to provide the ASP.NET MVC examples, since time expired before I was able to demonstrate during the presentation. I am including the Stick Contact Manager and Brick Contact Manager ASP.NET MVC versions, so you can download the source code. As discussed previously, the examples are primarily to provide the foundation for the design patterns and principles – not a full blown ASP.NET MVC web application with all the bells and whistles.

ASP.NET MVC is the perfect web architecture to promote our design patterns and principles we established throughout this series. The ASP.NET Web Forms paradigm is showing some age and not able to keep pace with evolving web technologies and increasing demands on applications. The Model-View-Controller design pattern is not page-centric like Web Forms, but instead is based on actions. The overall theme is separation, where the layers are maintainable, testable with a single responsibility. This sounds like everything we discussed, so let’s get started.

In Part IV, we refactored our prototype design and introduced the Stick Contact Manager. We applied several design patterns, which established a solid foundation for well-designed software. The design patterns and principles include Dependency Injection Principle (DIP), Separation of Concerns (SoC), Dependency Injection (DI) and Single Responsibility Principle (SRP). The Stick Contact Manager scored high marks during our evaluation, although we discovered one frustrating side-effect of the design – the client still must have knowledge of how to create the dependencies. We successfully eliminated the dependency creation throughout the majority of the objects, but we are forced to write significant code to create the dependencies.

The solution is centralizing the object creation or instantiation, so the client can delegate the task and knowledge of all the dependencies to another entity. This can also promote reusability, so the clients or consumers can also delegate this task to the same entity. This would eliminate the need for redundant client code required to create the dependencies.

So…let’s review the Stick Contact Manager MVC. Since we applied the Dependency Injection pattern, the dependencies are injected via the constructor. The core of MVC is the controller, which is responsible for processing the request and orchestrating the workflow to generate the appropriate response.

01
        private ContactsService _service;
02
        private ContactManager.Common.Repository.IContactRepository _repository;
03
        private ContactManager.Common.Services.INotificationService _notification;
04
 
05
        public ContactController() 
06
        {
07
            _repository = new ContactManager.Common.Repository.ContactRepository();
08
            _notification = new EmailService("myHost",
09
                                             "no-reply@test.com",
10
                                             "TEST", "Test Message");
11
            _service = new ContactsService(_repository,
12
                                           _notification,
13
                                           _notification);
14
        }
15

As discussed previously, the above Stick Contact Manager controller still must have knowledge of how to create the dependencies. As an alternative, we will introduce Inversion of Control (IoC) for our centralized object creation solution. An IoC container will handle the object creation, so now we can remove the majority of the instantiation code. In general, IoC inverts the relationship by the client delegating control to the container.

Let’s refactor the ContactController, so the Spring.NET IoC container will instantiate the object and inject all dependencies.

1
   public class ContactController : Controller
2
    {
3
        private ContactsService _service;
4
 
5
        public ContactController(ContactsService service)
6
        {
7
            _service = service;
8
        }

We significantly reduced the clutter regarding the instantiation of the objects, which has been delegated to the Spring.NET IoC container. How are we using Spring.NET IoC, because we do not see the code like the console application? This will require a small addition to the web.config, which allows the container to manage the instantiation and initialization of the participating objects. The following is the web.config entry to accomplish this task.

1
  <configSections>
2
    <sectionGroup name="spring">
3
      <section name="context" type="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc"/>
4
    </sectionGroup>
5
  </configSections>

How does the container know how to create the objects? Well, we will need to provide the instructions to the container. We will select the xml metadata configuration approach, so the object definition is contained in an external xml file. So…let’s look at the object definitions in the xml metadata files.

01
  <object type="MvcContactManager.Controllers.ContactController, MvcContactManager"
02
          singleton="false" >
03
    <constructor-arg ref="ContactsService"/>
04
  </object>
05
 
06
  <object id="ContactsService"
07
        type="ContactManager.Common.Services.ContactsService, ContactManager.Common">
08
    <!-- inline object -->
09
    <constructor-arg name="contactRepository">
10
      <object type="ContactManager.Common.Repository.ContactRepository, ContactManager.Common" />
11
    </constructor-arg>
12
    <constructor-arg name="helloNotificationService"    ref="HelloEmailNotificationService" />
13
    <constructor-arg name="goodbyeNotificationService"  ref="GoodbyeEmailNotificationService" />
14
  </object>
15
 
16
  <object id="HelloEmailNotificationService"
17
        type="ContactManager.Common.Services.EmailService, ContactManager.Common">
18
    <constructor-arg name="smtpHost"  value="${Smtp.Host}" />
19
    <constructor-arg name="sender"    value="${Email.Sender}" />
20
    <constructor-arg name="subject"   value="Hello!" />
21
    <constructor-arg name="message"   value="Hello Email Contact!" />
22
  </object>
23
 
24
  <!-- setter-based injection with abstract parent -->
25
  <object id="GoodbyeEmailNotificationService"
26
          type="ContactManager.Common.Services.EmailService, ContactManager.Common"
27
          parent="MailBase">
28
    <property name="Subject"  value="Hello!" />
29
    <property name="Message"  value="Hello Email Contact!" />
30
  </object>
31

We have 2 additional object definitions, so we can assign properties from external sources. In this case, we would like the web.config appSettings to be accessible to the objects. In the example above, the ${Smtp.Host} placeholder is replaced with the corresponding configuration appsettings value. The MailBase object contains the shared property values, which can be referenced using the parent attribute.

01
 <object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core">
02
    <property name="VariableSources">
03
      <list>
04
        <object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core">
05
          <property name="SectionName" value="appSettings" />
06
        </object>
07
      </list>
08
    </property>
09
  </object>
10
 
11
  <object id="MailBase">
12
    <property name="SmtpHost" value="${Smtp.Host}" />
13
    <property name="Sender"   value="${Email.Sender}" />
14
  </object>

The element object contains the instructions to instantiate and initialize an object. The id or name attribute is the  reference name, which is the value that is passed when requesting an object from the IoC container. The type attribute is the namespace qualified class name and fully qualified assembly name. The primary object child elements include the constructor-arg and property, which provide constructor and setter based dependency injection techniques. There are several options to the constructor element, which include name and index attributes. The container will attempt to match the signature of the appropriate constructor, so providing the correct name or index of the parameters is important. The value attribute is the static value, expression or placeholder. In the example above, the ${Smtp.Host} value is replaced with the configuration appsettings value. The ref attribute identifies the name or id of another object element, so the value is set to this object.

Please refer to Part V or presentation for additional information regarding the xml metadata.

The remaining component of Spring MVC is the application routing, which requires some plumbing code to complete. The following is the Stick Contact Manager global.asax file with the traditional implementation required for registering the routes.

01
using System;
02
using System.Web;
03
using System.Web.Mvc;
04
using System.Web.Routing;
05
 
06
namespace MvcContactManager
07
{
08
    public class MvcApplication : System.Web.HttpApplication
09
    {
10
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
11
        {
12
            filters.Add(new HandleErrorAttribute());
13
        }
14
 
15
        public static void RegisterRoutes(RouteCollection routes)
16
        {
17
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
18
 
19
            routes.MapRoute(
20
                "Default", // Route name
21
                "{controller}/{action}/{id}", // URL with parameters
22
                new { controller = "Home",
23
                      action = "Index",
24
                      id = UrlParameter.Optional } // Parameter defaults
25
            );
26
        }
27
 
28
        protected void Application_Start()
29
        {
30
            AreaRegistration.RegisterAllAreas();
31
 
32
            RegisterGlobalFilters(GlobalFilters.Filters);
33
            RegisterRoutes(RouteTable.Routes);
34
        }
35
    }
36
}

This is a lot of redundant code and hard-coded route registration process, which could be cumbersome with more complex implementations. The Spring MVC approach is much simpler and requires no additional coding to define the application routing.

01
using System.Web;
02
using System.Web.Mvc;
03
using System.Web.Routing;
04
using Spring.Web.Mvc;
05
using Spring.Context.Support;
06
 
07
namespace MvcContactManager
08
{
09
    public class MvcApplication : SpringMvcApplication
10
    {
11
 
12
    }
13
}

The routing is mapped to the appropriate controller, where the action invoker matches the public method. The action method of the controller handles the HTTP POST, which will call the ContactsService to process the request. The console application follows the same process, which collects the input from the client and calls ContactsService. The following is the ContactController, which handles the Add action and like the console Contact Manager will delegate the responsibility to the ContactsService. The controller is not concerned with what is required to add a contact.

01
using System;
02
using System.Web;
03
using System.Web.Mvc;
04
using ContactManager.Common.Services;
05
using MvcContactManager.ViewModels;
06
using ContactManager.Common.Model;
07
 
08
namespace MvcContactManager.Controllers
09
{
10
    public class ContactController : Controller
11
    {
12
        private ContactsService _service;
13
 
14
        public ContactController(ContactsService service)
15
        {
16
            _service = service;
17
        }
18
 
19
        [HttpGet]
20
        public ActionResult Add()
21
        {
22
            var model = new ContactViewModel();
23
            return View(model);
24
        }
25
 
26
        [HttpPost]
27
        public ActionResult Add(ContactViewModel inputForm)
28
        {
29
            var model = new ContactViewModel(inputForm.Name,
30
                                             inputForm.Email,
31
                                             inputForm.Phone);
32
 
33
            //Check if model is valid and call service to add contact
34
            if (this.ModelState.IsValid)
35
            {
36
                _service.AddContact(new Contact(model.Name,
37
                                                model.Email,
38
                                                model.Phone));
39
            }
40
 
41
            return View(model);
42
        }
43
    }
44
}
45

The ContactViewModel is the model, which identifies the properties that will be available to the view. We also decorate the class with validation attributes, which will provide the input validation. We will also separate the view and domain models. The domain model will remain with the Contact Manager common library, where it represents the data managed by the data tier (i.e. database).

01
namespace MvcContactManager.ViewModels
02
{
03
    public class ContactViewModel 
04
    {
05
        public ContactViewModel()
06
            : this(string.Empty,
07
                  string.Empty,
08
                  string.Empty) { }
09
 
10
        public ContactViewModel(string name,
11
                                string email,
12
                                string phone)
13
        {
14
            this.Name = name;
15
            this.Email = email;
16
            this.Phone = phone;
17
        }
18
 
19
        [Required(ErrorMessage="Name is required.")]
20
        [StringLength(40, 
21
                      ErrorMessage="Name cannot be greater than 40.")]
22
        public string Name { get; set; }
23
 
24
        [Required(ErrorMessage = "Email is required.")]
25
        [RegularExpression(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$",
26
                           ErrorMessage = "Email not valid format.")]
27
        public string Email { get; set; }
28
 
29
        [Required(ErrorMessage = "Phone is required.")]
30
        [RegularExpression(@"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}",
31
                           ErrorMessage = "Phone not valid format (###)###-#### or (###)###-####.")]
32
        public string Phone { get; set; }
33
    }
34
}

The following is the view, which will present our form to add contact information. The controller populated the model, which is available for the view to present dynamic data. The ViewBag and ViewData are also collections available for the view. NOTE: the ViewBag is available under ASP.NET MVC3 and .NET 4.

01
@model MvcContactManager.ViewModels.ContactViewModel
02
@{ ViewBag.Title = "Add Contact"; }
03
 
04
@using (Html.BeginForm("Add", "Contact", FormMethod.Post))
05
{
06
<div id="AddEditor">
07
    @Html.ValidationSummary("Please correct errors below and click Add again:")
08
    <fieldset>        
09
        <legend>Contact</legend>
10
        <table cellpadding="0" cellspacing="0">
11
            <tr>
12
                <td><span style="text-align: right;">Name</span></td>
13
                <td>@Html.TextBox("Name", @Model.Name)@Html.ValidationMessage("Name", "*")</td>
14
            </tr>
15
            <tr>
16
                <td><span style="text-align: right;">Email</span></td>
17
                <td>@Html.TextBox("Email", @Model.Email)@Html.ValidationMessage("Email", "*")</td>
18
            </tr>
19
            <tr>
20
                <td><span style="text-align: right;">Phone</span></td>
21
                <td>@Html.TextBox("Phone", @Model.Phone)@Html.ValidationMessage("Phone", "*")</td>
22
            </tr>
23
        </table>    
24
        <p><input type="submit" value="Add"/></p>    
25
    </fieldset>    
26
</div>                      
27
}

The following is a screenshot of the rendered page, which is after our initial postback and validation.

Brick Contact Manager MVC

The IoC alternatives including Service Locator and Factory Design patterns also provide solutions for centralizing the object creation. The Factory Design hides the complexities with a factory object that contains static methods returning the instantiated object. The Service Locator is also a central repository, which the client passes a key to retrieve an object. These options also work well with the core Dependency Injection Principle (DIP), Separation of Concern (SoC), Dependency Injection (DI) and Single Responsibility Principle (SRP). I always recommend exploring your options and pick the approach that works best for your project.

In summary, the Brick Contact Manager MVC solves the object creation responsibility problem. I have found that following the software design principles we have defined in Part II and implementing the patterns in Part IV are a good defense against premature end-of-life scenario for your applications. The addition of an IoC container will further promote the software design principles and add significant value to your product. You will find maintenance and change requests will be less painful.

I hope you found this series helpful and will be able to follow the concepts presented with your next project. We completed .NET and Java examples to illustrate the design patterns and practices can be applied to any OO language. We also built a console application and MVC client, which provides guidelines for integrating with the Spring IoC container. Please follow the below links to source code and related posts for additional information.

Source Code

Part V: Brick Contact Manager – Console Application

Previous: Part IV: Stick Contact Manager

Java Version: Part VI: Brick Contact Manager

Part VI: Java Brick Design – How to design and build better software for tomorrow?

0

Since the “How to design and build better software for tomorrow?” series, I received a few requests from members and colleagues in the Java community. Although the concepts and techniques can be applied to all OO languages, the code examples are C# .NET. Since the majority of my recent projects have been .NET, I just naturally start thinking and writing .NET. So…this post will be a port of the Brick Contact Manager .NET project to Java. If you did not follow the series then I encourage you to read the 4 previous entries as background. If you found this post and prefer the .NET flavor then click here.

In Part IV, we refactored our prototype design and introduced the Stick Contact Manager. We applied several design patterns, which established a solid foundation for well-designed software. The design patterns and principles include Dependency Injection Principle (DIP), Separation of Concerns (SoC), Dependency Injection (DI) and Single Responsibility Principle (SRP).

The following are the classes of the common library, which are referenced by the Brick Contact Manager console application. They have been refactored to follow the above design patterns, which were discussed in the previous entries of the series.

The Contact class is a POJO representing the model or domain object for our contact information. The IContactRepository is the interface or contract for our implementation of the data layer responsible for persistence of the contact information. The ContactRepository represents our concrete implementation.

01
package contactmanager.common.model;
02
 
03
import java.io.Serializable;
04
 
05
/**
06
 * Domain Object
07
 *
08
 */
09
public class Contact implements Serializable {
10
 
11
    private Integer id;
12
    private String name;
13
    private String emailAddress;
14
    private String mobilePhone;
15
 
16
    public Contact() {
17
    }
18
 
19
    public Contact (String Name,
20
                    String EmailAddress,
21
                    String MobilePhone) {
22
        this.name = Name;
23
        this.emailAddress = EmailAddress;
24
        this.mobilePhone = MobilePhone;
25
    }
26
 
27
    public Integer getId() {
28
        return this.id;
29
    }
30
 
31
    public void setId(Integer Id) {
32
        this.id = Id;
33
    }
34
 
35
    public String getName() {
36
        return this.name;
37
    }
38
 
39
    public void setName(String Name) {
40
        this.name = Name;
41
    }
42
 
43
    public String getMobilePhone() {
44
        return this.mobilePhone;
45
    }
46
 
47
    public void setModilePhone(String MobilePhone) {
48
        this.mobilePhone = MobilePhone;
49
    }
50
 
51
    public String getEmailAddress() {
52
        return this.emailAddress;
53
    }
54
 
55
    public void setEmailAddress(String EmailAddress) {
56
        this.emailAddress = EmailAddress;
57
    }
58
 
59
    @Override
60
    public String toString()
61
    {
62
        return new StringBuilder()
63
                .append("Name=")
64
                .append(this.name)
65
                .append("\nEmailAddress=")
66
                .append(this.emailAddress)
67
                .append("\nMobilePhone=")
68
                .append(this.mobilePhone)
69
                .toString();
70
    }
71
}

01
package contactmanager.common.repository;
02
 
03
import contactmanager.common.model.Contact;
04
 
05
/**
06
 * ContactRepository contract
07
 * Create one or more implementations.
08
 */
09
public interface IContactRepository {
10
 
11
    void save(Contact contact);
12
}

01
package contactmanager.common.repository;
02
 
03
import contactmanager.common.model.Contact;
04
 
05
/**
06
 * Concrete implementation to persist contact to data store
07
 * I am now separated with a single responsibility to be maintainable,
08
 * reusable and testable!
09
 */
10
public class ContactRepository implements IContactRepository {
11
 
12
    public ContactRepository() { }
13
 
14
    @Override
15
    public void save(Contact Contact) {
16
        System.out.println("ContactRepository.Save: \n" +
17
                Contact.toString());
18
        //TODO: code to persist contact
19
    }
20
}

If we introduce a new technique to persist the contact information then building a new contact repository implementation would be simple. The design patterns will enable us to simplify the process of swapping the new contact repository implementation, so the enterprise application would require no coding changes. This technique is also beneficial for prototyping, so you are not forced to modify your high-level classes. You are creating classes that rely on abstractions or interfaces instead of concrete implementations, so you have the flexibility to swap implementations without significant impact – the ripple effect.

We apply the same technique for the notification services, where the INotificationService is the abstraction/interface and we can create any number of concrete implementations. In our example below, we built the EmailService to provide email capabilities. The same benefits apply as discussed previously, so we can create new concrete implementations for notification services without causing a ripple effect throughout the system. The change is less painful using the design patterns.

01
package contactmanager.common.services;
02
 
03
import contactmanager.common.model.Contact;
04
/**
05
 * NotificationService contract
06
 * Create one or more implementations. Try using an abstract
07
 * class if shared features are beneficial to the implementations.
08
 */
09
public interface INotificationService {
10
 
11
    void send(Contact Contact);
12
 
13
    String getMessage();
14
 
15
    void setMessage(String Message);    
16
}

001
002
/**
003
 * Concrete implementation to send email notifications
004
 * I am now separated with a single responsibility to be maintainable,
005
 * reusable and testable!
006
 */
007
public class EmailService implements INotificationService {
008
 
009
    private String message;
010
    private String subject;
011
    private String sender;
012
    private String smtpHost;
013
 
014
    public EmailService() { }
015
 
016
    public EmailService(String SmtpHost,
017
                        String Sender,
018
                        String Subject,
019
                        String Message) {
020
            this.message = Message;
021
            this.subject = Subject;
022
            this.sender = Sender;
023
            this.smtpHost = SmtpHost;
024
    }
025
 
026
    @Override
027
    public void send(Contact Contact)
028
    {
029
        System.out.println("EmailService.Send: \n" +
030
                toString() +
031
                Contact.getName());
032
        //TODO: email
033
    }
034
 
035
    @Override
036
    public String toString()
037
    {
038
        return new StringBuilder()
039
                .append("SmtpHost=")
040
                .append(this.smtpHost)
041
                .append("\nSender=")
042
                .append(this.sender)
043
                .append("\nSubject=")
044
                .append(this.subject)
045
                .append("\nMessage=")
046
                .append(this.message)
047
                .toString();
048
    }
049
 
050
    /**
051
     * @return the Message
052
     */
053
    @Override
054
    public String getMessage() {
055
        return this.message;
056
    }
057
 
058
    /**
059
     * @param Message the Message to set
060
     */
061
    @Override
062
    public void setMessage(String Message) {
063
        this.message = Message;
064
    }
065
 
066
    /**
067
     * @return the Subject
068
     */
069
    public String getSubject() {
070
        return this.subject;
071
    }
072
 
073
    /**
074
     * @param Subject the Subject to set
075
     */
076
    public void setSubject(String Subject) {
077
        this.subject = Subject;
078
    }
079
 
080
    /**
081
     * @return the Sender
082
     */
083
    public String getSender() {
084
        return this.sender;
085
    }
086
 
087
    /**
088
     * @param Sender the Sender to set
089
     */
090
    public void setSender(String Sender) {
091
        this.sender = Sender;
092
    }
093
 
094
    /**
095
     * @return the SmtpHost
096
     */
097
    public String getSmtpHost() {
098
        return this.smtpHost;
099
    }
100
 
101
    /**
102
     * @param SmtpHost the SmtpHost to set
103
     */
104
    public void setSmtpHost(String SmtpHost) {
105
        this.smtpHost = SmtpHost;
106
    }
107
}

The ContactsService class is our final common library object, which is the called by the Brick Contact Manager user interface to handle our business logic. It is responsible for orchestrating the objects required to perform complete the desired client request, which is add a contact in our example. We do not have logic to email or persist data, since these tasks have been delegated to the appropriate objects. The design is decoupled from the concrete implementations, since the constructors accept abstractions/interfaces instead of concrete types.

01
package contactmanager.common.services;
02
 
03
import contactmanager.common.model.Contact;
04
import contactmanager.common.repository.IContactRepository;
05
/**
06
 * High-level concrete contacts service - called by the client
07
 * I am not married to low-level concrete dependencies, so any
08
 * changes will no longer affect me. I now depend on interfaces
09
 * or abstract classes.
10
 */
11
public class ContactsService {
12
 
13
    private IContactRepository ContactRepository;
14
    private INotificationService NotificationService;
15
 
16
    //dependencies are now injected using the constructor
17
    public ContactsService(IContactRepository ContactRepository,
18
                           INotificationService NotificationService)
19
    {
20
        this.ContactRepository = ContactRepository;
21
        this.NotificationService = NotificationService;
22
    }
23
 
24
    public void addContact(Contact Contact)
25
    {
26
        //code is simple and easy to understand!
27
        System.out.println("ContactsService.AddContact: \n" +
28
                Contact.toString());
29
        this.ContactRepository.save(Contact);
30
        this.NotificationService.send(Contact);
31
    }
32
}

The Stick Contact Manager (see Part IV) scored high marks during our evaluation, although we discovered one frustrating side-effect of the design – the client still must have knowledge of how to create the dependencies. We successfully eliminated the dependency creation throughout the majority of the objects, but we are forced to write significant code to create the dependencies.

The solution is centralizing the object creation or instantiation, so the client can delegate the task and knowledge of all the dependencies to another entity. This can also promote reusability, so the clients or consumers can also delegate this task to the same entity. This would eliminate the need for redundant client code required to create the dependencies.

As discussed previously, the Stick Contact Manager client still must have knowledge of how to create the dependencies. As an alternative, we will introduce Inversion of Control (IoC) for our centralized object creation solution. An IoC container will handle the object creation, so now we can remove the majority of the code and just request the object. In general, IoC inverts the relationship by the client delegating control to the container. In this example, we selected Spring for the job.

So…let’s refactor the client for the Brick Contact Manager to call the Spring IoC container and request the ContactsService (download source code). The container will instantiate the object and injects all dependencies, so the object is ready to use without additional initialization.

01
package brickcontactmanager;
02
 
03
import contactmanager.common.model.Contact;
04
import contactmanager.common.services.ContactsService;
05
import org.springframework.context.ApplicationContext; 
06
import org.springframework.context.support.ClassPathXmlApplicationContext;
07
 
08
/** 
09
* Simple console application to illustrate the design patterns of ContactManager
10
*
11
*/
12
public class BrickContactManager {
13
 
14
    /**
15
     * @param args the command line arguments
16
     */
17
    public static void main(String[] args) {
18
        System.out.println("*** BrickContactManager ***");
19
        //set reference to IoC container
20
        ApplicationContext context = 
21
                new ClassPathXmlApplicationContext("applicationContext.xml",
22
                BrickContactManager.class);
23
        /* request object from container - client is no longer aware of how
24
           to construct the object and its' dependencies!!! */
25
        ContactsService service = (ContactsService)context.getBean( "ContactsService" );
26
 
27
        service.addContact(new Contact("John Doe",
28
                                       "jwalton@test.com",
29
                                       "0000000000"));
30
    }
31
}

It was just a few lines of code for the client and we significantly reduced the clutter regarding the instantiation of the objects, which has been delegated to the Spring IoC container. How does the container know how to create the objects? Well, we will need to provide the instructions to the container. We will select the xml metadata configuration approach, so the bean definition is contained in an external xml file. So…let’s look at the object definitions in the xml metadata files.

01
<?xml version="1.0" encoding="UTF-8"?>
02
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
03
<beans>
04
    <bean id="ContactsService"
05
          class="contactmanager.common.services.ContactsService">
06
        <!-- inline object -->
07
        <constructor-arg>
08
            <bean class="contactmanager.common.repository.ContactRepository" />
09
        </constructor-arg>
10
        <constructor-arg ref="EmailService" />
11
    </bean>
12
    <bean id="EmailService"
13
          class="contactmanager.common.services.EmailService" >
14
        <constructor-arg value="dummy.com" />
15
        <constructor-arg value="test@dummy.com" />
16
        <constructor-arg value="Hello!" />
17
        <constructor-arg value="Hello Email Contact!" />
18
    </bean>
19
</beans>

The element bean contains the instructions to instantiate and initialize an object. The id or name attribute is the reference name, which is the value that is passed when requesting an object from the IoC container. The class attribute is the namespace qualified class name. The primary bean child elements include the constructor-arg and property, which provide constructor and setter based dependency injection techniques.The value attribute is the static value, expression or placeholder. The ref attribute identifies the name or id of another bean element, so the value is set to this object.

Our Brick Contact Manager xml metadata example is only scratching the surface of the options available for defining your objects. Bean configuration and the popular elements and attributes supporting instantiation, inheritance, lifecycle, scope and the injection types (setter and property) are available.

The following is the output from the NetBeans IDE, where you can trace the calls based on the console writes.

The choice of the dependency injection type (i.e. constructor, setter or method) is sometimes a personal choice. I prefer defining a constructor for mandatory dependencies and setter properties for optional items. If you have too many mandatory items then your constructors become difficult to manage and configure using IoC.

Spring provides a robust set of IoC features that are too many to present in this post. You can download the Brick Contact Manager and review the code. You will find making changes is simple. The NetBeans and Eclipse development environments provide the libraries and templates to support Spring, so this minimizes the learning curve for Spring.

In summary, the Brick Contact Manager complements the Stick Contact Manager and solves the object creation responsibility problem. I have found that following the software design principles we have defined in Part II and implementing the patterns in Part IV are a good defense against premature end-of-life scenario for your applications. The addition of an IoC container will further promote the software design principles and add significant value to your product. You will find maintenance and change requests will be less painful.

I hope you found this series helpful and will be able to follow the concepts presented with your next project. I still receive messages from colleagues of previous projects as they continue to promote the design patterns and practices discussed in this series. If you are currently working a project then take a few minutes and perform an evaluation using our software design principles. Would your project benefit from the design patterns and concepts?

Source Code

Go to Top