Tuesday, December 4, 2012

Creational Patterns: Builder

In this post I am going to show you how to implement the Builder design pattern in Java.

Solution offered by the pattern

This pattern separates the construction of a complex object from its representation, in a way that the same construction process allows to create different representations. 
To do so we must use an object, the Director, that determines the product construction logic and sends those instruction to an object, the Builder, responsible for the product construction. Since the product to be carrued out are of different nature, there will be particular Builders for every kind of product, but one only Director. In the process of construction the Director calls invokes the chosen Builder's methods based on the type of the desired product (the Builders should implement a common interface to allow the Director to interact with all those).

Pattern Structure


Builder Design Pattern Class Diagram
Design pattern application - schema model


Builder Application  Balls schema

Partecipants

  • Builder: Abstract class BallBuilder:
- Declares an interface for the operations that create the parts of the object Product;
- Implements the default operations for every operation. 

  •  ConcreteBuilder: the classes BasketBallBuilder and VolleyBallBuilder:
- They provide the concrete operations for the interface correspondant to bhe Builder;
- Construct and assemblate the parts of a Product; 
- Provides a method that returns the created Product. 

  • Director: class Director 
- Construct the Product invoking the methods of the interface of the builder.

  • Product: classes Ball, BasketBall and VolleyBall
- Represents the complex object in construction. The ConcreteBuilders return the internal representation of the products;
- Includes classes that defines the parts of a Product. 

 Code Description
I've declared the abstract class BallBuilder extended by the ConcreteBuilders for the construction of every kind of ball. The class BallBuilder contains all the methods that the ConcreteBuilder could override, and they do implement only those necessary to construct the Product; this is why the BallBuilder provides all the methods a default code, in this case null code; the only abstract method is getBall() that all the ConcreteBuilders must implement to return the constructed object.

 
package com.fa.builderdesignpattern.builder;

import com.fa.builderdesignpattern.product.Ball;

public abstract class BallBuilder {
 
    
    public abstract Ball getBall();
    public void createNewBallProduct() {};
    public void buildWeight() {};
    public void buildCircumference() {};
    public void buildColor() {};
    public void buildPrice() {};
 
}

This class presents a set of methods declared with a default implementation and the first method declared abstract that must be implement from the builders to return the different kind of objects.
The methods presented are those needed to construct the product and the abstract one that returns the constructed product of type Ball.
The following classes are the ConcreteBuilders and contain the code necessary to return the instantiated product:
 
package com.fa.builderdesignpattern.builder;

import com.fa.builderdesignpattern.product.Ball;
import com.fa.builderdesignpattern.product.BasketBall;

public class BasketBallBuilder extends BallBuilder {

 protected Ball basketBall;
 
 @Override
 public void buildWeight() {
  basketBall.setWeight("624 g");
 }

 @Override
 public void buildCircumference() {
  basketBall.setCircumference("75-75.88 cm");
 }

 @Override
 public void buildColor() {
  basketBall.setColor("Orange surface with black ribs and a possible logo is the traditional color scheme of basketballs.");
 }

 @Override
 public void buildPrice() {
  basketBall.setPrice("$95");
 }

 @Override
 public Ball getBall() {
  return basketBall;
 }

 @Override
 public void createNewBallProduct() {
  basketBall = new BasketBall();
 }

}

 
package com.fa.builderdesignpattern.builder;

import com.fa.builderdesignpattern.product.Ball;
import com.fa.builderdesignpattern.product.VolleyBall;

public class VolleyBallBuilder extends BallBuilder {

 Ball volleyBall;
 
 @Override
 public void buildWeight() {
  volleyBall.setWeight("270 g");
 }

 @Override
 public void buildCircumference() {
  volleyBall.setCircumference("65-67 cm");
 }

 @Override
 public void buildColor() {
  volleyBall.setColor("Volleyballs may be solid white or a combination of two or three different easily distinguishable colors.");
 }

 @Override
 public void buildPrice() {
  volleyBall.setPrice("$60");
 }

 @Override
 public Ball getBall() {
  return volleyBall;
 }

 @Override
 public void createNewBallProduct() {
  volleyBall = new VolleyBall();
 }
}

As you can see the concrete builders do override the default behaviour defined in the AbstractBuilder and the method getBall() that was declared abstract in the AbstractBuilder is now implemented to return the constructed Ball. The Director class receives a reference to a ConcreteBuilder and will execute its methods to construct the Product. The Director in this example has a method createNewBallProduct() to instantiate a new Ball and a method constructBall() that is called to set the properties of the new created product. Finally the method getBall() returns the new instantiated Ball.
package com.fa.builderdesignpattern.director;

import com.fa.builderdesignpattern.builder.BallBuilder;
import com.fa.builderdesignpattern.product.Ball;

public class Director {
 
 private BallBuilder ballBuilder;
  
    public void setBallBuilder(BallBuilder bb) { ballBuilder = bb; }
    public Ball getBall() { return ballBuilder.getBall(); }
 
    public void constructBall() {
     ballBuilder.createNewBallProduct();
     ballBuilder.buildWeight();
     ballBuilder.buildCircumference();
     ballBuilder.buildColor();
     ballBuilder.buildPrice();
    }
 
}

Note that the Director is not aware of which type of ConcreteBuilder it is working with because it is managed through the common interface of the Builders (BallBuilder). The class BuilderExample contains the main that demonstrates the pattern realizing an instance of both the Builders. Note that the type of ConcreteBuilder is chosen only at this level. Lets now see the Products: in this example I have defined an abstract superclass Ball that is extended by the concrete Products VolleyBall and BasketBall.
package com.fa.builderdesignpattern.product;

public abstract class Ball {
 
 private String weight = "";
 private String circumference = "";
 private String color = "";
 private String price = "";
 
 public void setWeight(String weight) { this.weight = weight; }
 
 public void setCircumference(String circumference) { this.circumference = circumference; }
 
 public void setColor(String color) { this.color = color; }

 public void setPrice(String price) { this.price = price; }
 
 public abstract String bounce();
 
 public String toString() {
  return "weight: " + weight +
    ", circumference: " + circumference + 
    ", color: " + color + 
    ", price: " + price + 
    ", " + bounce();
    
 }
}

package com.fa.builderdesignpattern.product;

public class BasketBall extends Ball {

 @Override
 public String bounce() {
  return "BasketBall BOUNCE"; 
 }

}

package com.fa.builderdesignpattern.product;

public class VolleyBall extends Ball {

 @Override
 public String bounce() {
  return "VolleyBall BOUNCE"; 
 }

}

The abstract class Ball defines the properties and methods common to the concrete Products and defines the abstract method bounce() that its child override defining their own behaviours. Example execution
BasketBall: weight: 624 g
circumference: 75-75.88 cm
color: Orange surface with black ribs and a possible logo is the traditional color scheme of basketballs.
price: $95
BasketBall BOUNCE

VolleyBall: weight: 270 g
circumference: 65-67 cm
color: Volleyballs may be solid white or a combination of two or three different easily distinguishable colors.
price: $60
VolleyBall BOUNCE

Thursday, November 29, 2012

Creational Patterns: Abstract Factory

In this post I am going to show you implement the Abstract Factory pattern in Java. 

Description

The Abstract Factory pattern presents an interface for creating a family of products in a way that the client that uses those doesn't know anything about the concrete classes.


Solution offered by the pattern

This pattern is based on the definition of interfaces for every kind of product. There will be concrete classes that implement those interfaces that allow clients to make use of the products. The product families will be created by an object known as factory.
Every family has its particular factory used by the client to create products instances. Because the aim is not to tie the client to a specific factory, these factory implement a common interface known by the client.

Pattern structure


Abstract Factory Design Pattern Structure

Design pattern application - schema model


Abstract Factory Application - Widgets schema

Partecipants: 

  • AbstractFactory: interface WidgetFactory
- declares operations that create and return products.  
- the returned products are all AbstractProduct
  • ConcreteFactory: classes WindowsWidgetFactory, LinuxWidgetFactory, MacWidgetFactory. 
- implements the AbstractFactory. Creates and returns specific objects correnspondent to specific objects (ConcreteProduct).
  • AbstracProduct: interfaces Widget, TextBox, ComboBox, ListBox.
- define the operation that characterize the different generic types of products.
  • ConcreteProduct: classes WindowsTextBox, LinuxTextBox, MacTextBox, WindowsComboBox, LinuxComboBox, MacComboBox, WindowsListBox, LinuxListBox, MacListBox.
- define the products created by the ConcreteFactory. 
  • Client: class Client.
- uses the AbstractFactory to call the ConcreteFactory of a product family.   
- uses products by their interface AbstractProduct.

Code Description

Create the interfaces that the classes of every product family will implement. Widget is a marker interface used to identify interface components, while the interfaces TextBox, ComboBox and ListBox define the methods the clients invoke to draw the components. 


 
package com.fa.abstractfactory.product;

public interface Widget { }
 
package com.fa.abstractfactory.product;

public interface TextBox extends Widget {

	public void draw();
}
 
package com.fa.abstractfactory.product;

public interface ListBox extends Widget {

	public void draw();
}
 
package com.fa.abstractfactory.product;

public interface ComboBox extends Widget {

	public void draw();
}

We do implement the concrete classes of the products.


 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;

public class LinuxComboBox implements ComboBox{

	private List comboList;
	
	public LinuxComboBox(List list) {
		System.out.println("LinuxComboBox");
		this.comboList = list;
	}
	
	public void draw() {
		for(int i=0; i < comboList.size(); i++) {
			System.out.println("- " + comboList.get(i) + " -");
		}
	}

}

 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;

public class MacComboBox implements ComboBox {

	private List comboList;
	
	public MacComboBox(List list) {
		System.out.println("MacComboBox");
		this.comboList = list;
	}
	public void draw() {
		for(int i=0; i < comboList.size(); i++) {
			System.out.println("| " + comboList.get(i) + " |");
		}
	}
}


 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;

public class WindowsComboBox implements ComboBox {

	private List comboList;
	
	public WindowsComboBox(List list) {
		System.out.println("WindowsComboBox");
		this.comboList = list;
	}
	public void draw() {
		for(int i=0; i < comboList.size(); i++) {
			System.out.println("< " + comboList.get(i) + " >");
		}
	}

}


 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ListBox;

public class LinuxListBox implements ListBox{

	private List list;
	
	public LinuxListBox(List list) {
		System.out.println("LinuxListBox");
		this.list = list;
	}
	
	public void draw() {
		for(int i=0; i < list.size(); i++) {
			System.out.println("- " + list.get(i) + " -");
		}
	}

}

 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ListBox;

public class MacListBox implements ListBox{

	private List list;
	
	public MacListBox(List list) {
		System.out.println("MacListBox");
		this.list = list;
	}
	public void draw() {

		for(int i=0; i < list.size(); i++) {
			System.out.println("| " + list.get(i) + " |");
		}
	}

}

 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ListBox;

public class WindowsListBox implements ListBox {

	private List list;
	
	public WindowsListBox(List list) {
		System.out.println("WindowsListBox");
		this.list = list;
	}
	public void draw() {

		for(int i=0; i < list.size(); i++) {
			System.out.println("< " + list.get(i) + " >");
		}
	}
	
}

 
package com.fa.abstractfactory.product.impl;

import com.fa.abstractfactory.product.TextBox;

public class LinuxTextBox implements TextBox {

	private String text;
	
	public LinuxTextBox(String value) {
		System.out.println("LinuxTextBox");
		this.text = value;
	}
	
	public void draw() {
		System.out.println("- " + text + " -");
	}

}

 
package com.fa.abstractfactory.product.impl;

import com.fa.abstractfactory.product.TextBox;

public class MacTextBox implements TextBox{

	private String text;
	
	public MacTextBox(String value) {
		System.out.println("MacTextBox");
		this.text = value;
	}
	
	public void draw() {
		System.out.println("| " + text + " |");
	}

}

 
package com.fa.abstractfactory.product.impl;

import com.fa.abstractfactory.product.TextBox;

public class WindowsTextBox implements TextBox {

	private String text;
	
	public WindowsTextBox(String text) {
		System.out.println("WindowsTextBox");
		this.text = text;
	}
	
	public void draw() {
		System.out.println("< " + text + " >");
	}

}

The AbstractFactory interface defines the methods that return the generic type of Products.

 
package com.fa.abstractfactory.factory;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;

public interface WidgetFactory {
	TextBox createTextBox(String value);
	ListBox createListBox(List list);
	ComboBox createComboBox(List list);
}

Than we define the ConcreteFactory classes that create and return the concrete product for each family


 
package com.fa.abstractfactory.productfactory;

import java.util.List;

import com.fa.abstractfactory.factory.WidgetFactory;
import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;
import com.fa.abstractfactory.product.impl.LinuxComboBox;
import com.fa.abstractfactory.product.impl.LinuxListBox;
import com.fa.abstractfactory.product.impl.LinuxTextBox;

public class LinuxWidgetFactory implements WidgetFactory{

	@Override
	public TextBox createTextBox(String value) {
		return new LinuxTextBox(value);
	}

	@Override
	public ListBox createListBox(List list) {
		return new LinuxListBox(list);
	}

	@Override
	public ComboBox createComboBox(List list) {
		return new LinuxComboBox(list);
	}

}

 
package com.fa.abstractfactory.productfactory;

import java.util.List;

import com.fa.abstractfactory.factory.WidgetFactory;
import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;
import com.fa.abstractfactory.product.impl.MacComboBox;
import com.fa.abstractfactory.product.impl.MacListBox;
import com.fa.abstractfactory.product.impl.MacTextBox;

public class MacWidgetFactory implements WidgetFactory{

	@Override
	public TextBox createTextBox(String text) {
		return new MacTextBox(text);
	}

	@Override
	public ListBox createListBox(List list) {
		return new MacListBox(list);
	}

	@Override
	public ComboBox createComboBox(List list) {
		return new MacComboBox(list);
	}

}

 
package com.fa.abstractfactory.productfactory;

import java.util.List;

import com.fa.abstractfactory.factory.WidgetFactory;
import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;
import com.fa.abstractfactory.product.impl.WindowsComboBox;
import com.fa.abstractfactory.product.impl.WindowsListBox;
import com.fa.abstractfactory.product.impl.WindowsTextBox;

public class WindowsWidgetFactory implements WidgetFactory{

	@Override
	public TextBox createTextBox(String text) {
		return new WindowsTextBox(text);
	}

	@Override
	public ListBox createListBox(List list) {
		return new WindowsListBox(list);
	}

	@Override
	public ComboBox createComboBox(List list) {
		return new WindowsComboBox(list);
	}

}


The Client class defines the objects that every family product uses. Its constructor receives an object correnspondent to a particular family. The test method defines an instance for every particular family product and applies the different methods defined by the interface that the products implement. Note that the Client uses the Products without knowing which concrete object they belong to.
package com.fa.abstractfactory.client;

import java.util.Arrays;
import java.util.List;

import com.fa.abstractfactory.factory.*;
import com.fa.abstractfactory.product.impl.MacComboBox;
import com.fa.abstractfactory.product.impl.MacListBox;
import com.fa.abstractfactory.product.impl.MacTextBox;
import com.fa.abstractfactory.productfactory.MacWidgetFactory;

public class Client {

	private WidgetFactory factory;
	
	public Client(WidgetFactory factory) {
		this.factory = factory;
	}
	
	public void test() {
		
		factory.createTextBox("Text").draw();
		
		List list = Arrays.asList("First", "Second", "Third");
		factory.createListBox(list).draw();
		
		factory.createComboBox(list).draw();

	}
	
}


Next there is an example class that instantiates 3 Client objects passing to their constructor a family of product:
package com.fa.abstractfactory.test;

import com.fa.abstractfactory.client.Client;
import com.fa.abstractfactory.productfactory.LinuxWidgetFactory;
import com.fa.abstractfactory.productfactory.MacWidgetFactory;
import com.fa.abstractfactory.productfactory.WindowsWidgetFactory;

public class AbstractFactoryExample {
	
	public static void main(String[] args) {
		
		Client client1 = new Client(new MacWidgetFactory());
		client1.test();
		
		Client client2 = new Client(new LinuxWidgetFactory());
		client2.test();
		
		Client client3 = new Client(new WindowsWidgetFactory());
		client3.test();
	}
	
}


Next image shows you the console output, resulting from launching the previous starter class.
MacTextBox
| Text |
MacListBox
| First |
| Second |
| Third |
MacComboBox
| First |
| Second |
| Third |
LinuxTextBox
- Text -
LinuxListBox
- First -
- Second -
- Third -
LinuxComboBox
- First -
- Second -
- Third -
WindowsTextBox
< Text >
WindowsListBox
< First >
< Second >
< Third >
WindowsComboBox
< First >
< Second >
< Third >

Sunday, November 25, 2012

Design Patterns

Creational Patterns

Creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to de design. Creational design patterns solve this problem somehow controlling this object creation.

Creational design patterns are further categorized into Object-creational patterns and Class-creational patterns, where Object-creational patterns deal with Object creation and Class-creational patterns deal with Class-instantiation. In greater details, Object-creational patterns defer part of its object creation to another object, while Class-creational patterns defer its objection creation to subclasses.

Five well-known design patterns that are part of creational patterns are:

  • Abstract Factory
  • Builder
  • Factory
  • Prototype
  • Singleton

Structural Patterns

Structural design patterns are those that ease the design by identifying a simple way to realize relationship between entities. Structural class-creation patterns use inheritance to compose interfaces. Structural object-patterns define ways to compose objects to obtain new functionality.

Example of structural patterns include:

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Extensibility
  • Facade
  • Proxy

Behavioral Patterns

Behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. These patterns increase flexibility in carrying out this communication.

Examples of this type of design patterns include:

  • Chain of Responsibility
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template
  • Visitor

In my next posts I am going to show you how to implement some of the patterns listed above.

Tuesday, February 7, 2012

Maven and Spring WS - contract first

In this post I am going to show you how to configure and create a Web Service using Spring WS. 
Web Services developed with Spring are called contract-first Web Services because these starts with the XML Schema/WSDL contract first followed  by the Java code. In the first part of this tutorial I show you how to create the contract of the web service with XML and XSD containing request and response objects. In the second part I show you how to imlement the Web Service with Spring WS.

The most important thing when doing contract-first Web Services is to think in terms of XML. It is the XML that is sent across the wire, and you should focus on that- The fact that Java is used to implement the Web Service is an implementation detail.

The Web Service I am going to create is used to call the Google Maps services that returns an image of a locality. The reaquest contains an address or coordinates of a point in the earth or the request contains addresses or coordinates of 2 points and the response image contains the route to get from the origin to destination.

Messages
In this section I will focus on the XML messages that are sent to and from the Web Service.

As I wrote above, two of the four requests sent to the Web Service contain a coordinate (latitude, longitude) of a point in the earth or a String address to be searched by the Google Maps services, this is the declaration of these kind of objects using XSD: 

Below an example of these two XML object types: 








The next two request types are just a little different from the two above. These will contain two coordinates or two addresses to calculate the route to get from origin to destination. The last type has also another attribute called waypoints that is a List of intermediate addresses which to pass through to get to destination: 

 Next an example of these two object requests: 











The service contract based on the XSD types above is a WSDL file. It is not required that we write it by hand because Spring creates it for us when we deploy the Web Service in a Application Server. 

Web Service configuration
We can now create a new project to implements the Web Service using Java. 
I will use Maven 2 to create the initial project structure.
Once created the project structure, under the src/main/webapp folder we will find the standard web application deployment descriptor WEB-INF/web.xml which defines a Spring-WS MessageDispatcherServlet and maps all incoming requests to this servlet.

In addition to the above WEB-INF/web.xml file, we need to create the Spring configuration file WEB-INF/spring-ws-servlet.xml. This file contains all the Spring beans related to the WS such as the Web Service Implementation, the Endpoint and the contracts of the Web Service (XSD and WSDL). The name of this file is derived from the name of the attendant servlet (in this case spring-ws) with -servlet.xml appended to it.  Below we can see the configuration file: 
The first bean I have declared is a PropertyPlaceholder used to import some default values from a properties file declared in a folder on the root of the Application Server. The other bean declared are the Service Implementation that injects some default properties, by Inversion of Control, that get the values from the property placeholders from the file imported above. Follows the Endpoint declaration which injects the web service bean to a constructor argument. The last two beans represent the contract of the Web Service: XSD definition and WSDL definition that gets some properties to be injected. 

There's another configuration file that we need to create: it is the pom.xml that is the Maven configuration file used to list the dependencies of the application and information such as the build process. Follows my pom.xml: 

The dependencies needed for this project are Spring-WS and the libraries needed to test the application. There is also the maven plugin for the build process. 

The Endpoint
In Spring WS, we need to implement Endpoints to handle incoming XML requests. It is created by annotating the class with the @Endpoint annotation and it has one or more methods to handle the incoming requests each related to a Web Service method. 
Before creating the Endpoint class I have used JAX-B to create the Java classes related to the XSD types I have defined earlier for the requests and responses. 
The command to be used to generate the classes is: xjc SchemaFile.xsd.
Follows my web service endpoint: 


package com.faeddalberto.googlews.endpoint;

@Endpoint
public class GoogleServicesEndpoint {

    private GoogleServices service;
 
    @Autowired
    public GoogleServicesEndpoint(GoogleServices service) {
        this.service = service;
    }
 
    @PayloadRoot(localPart="ImageFromCoordinatesRequest", 
        namespace="http://www.faeddalberto.com/GoogleServicesContracts/types")
    public GoogleServicesResponse getImageFromCoordinates(
            ImageFromCoordinatesRequest aRequest){

        return service.getImageFromCoordinates(aRequest);
    }

    @PayloadRoot(localPart="ImageFromAddressRequest", 
        namespace="http://www.faeddalberto.com/GoogleServicesContracts/types")
    public GoogleServicesResponse getImageFromAddress(
            ImageFromAddressRequest aRequest){

        return service.getImageFromAddress(aRequest);
    }
 
    @PayloadRoot(localPart="ImageRouteFromCoordinatesRequest",
        namespace="http://www.faeddalberto.com/GoogleServicesContracts/types")
    public GoogleServicesResponse getImageRouteFromCoordinates(
            ImageRouteFromCoordinatesRequest aRequest){

        return service.getImageRouteFromCoordinates(aRequest);
    }
 
    @PayloadRoot(localPart="ImageRouteFromAddressesRequest",
        namespace="http://www.faeddalberto.com/GoogleServicesContracts/types")
    public GoogleServicesResponse getImageRouteFromAddresses(
            ImageRouteFromAddressesRequest aRequest){

        return service.getImageRouteFromAddresses(aRequest);
    }
}

This Endpoint class, annotated with the @Endpoint annotation, has a constructor to which is injected the Web Service Implementation Bean as I showed you in the Spring configuration file.
The @PayloadRoot annotations tells Spring WS that the methods are suitable for handling XML messages.
This annotation uses some attributes: the localpart attribute that defines which is the request that the method handles and the namespace attribute that defines the namespace which the request is related to. The four methods declared in the Endpoint class call the four web service methods and all four get a different request as argument that are the classes defined by the JAX-B APIs from the XSD.
All the methods return the same response that is the response of the web service: an image related to the request or an error message if any error has occurred in the web service.

Implementing the Web Service
Let's now give a look at the Java code to implement the Web Service. As usual we have the Interface that declares the service operations and the Service Implementation Bean that implements these operations.
Follows the web service interface:

package com.faeddalberto.googlews.service;

public interface GoogleServices {

    public GoogleServicesResponse getImageFromCoordinates(
ImageFromCoordinatesRequest request);
 
    public GoogleServicesResponse getImageFromAddress(
        ImageFromAddressRequest request);
 
    public GoogleServicesResponse getImageRouteFromCoordinates(
        ImageRouteFromCoordinatesRequest request);
 
    public GoogleServicesResponse getImageRouteFromAddresses(
        ImageRouteFromAddressesRequest request);

}


The Web Service Interface has four methods declared that are the methods the Web Service Implementation Bean implements:


package com.faeddalberto.googlews.service;

public class GoogleServicesImpl implements GoogleServices {

    private static final String SENSOR = "sensor=true";
    private static final String QUESTION_MARK = "?";
    private static final String AMPERSAND = "&";
    private static final String PIPE = "|"; 

    private String directionUrl;
    private String staticUrl;
 
    private String mapType;
    private String zoom;
    private String size;
    private String path;
    private String markers;
 
    private String center;
    private String origin;
    private String destination;
    private String wayPoints; 
 
    public GoogleServicesResponse getImageFromCoordinates(
            ImageFromCoordinatesRequest request) {
  
        System.out.println("getImageFromCoordinates");
  
        GoogleServicesResponse response = new GoogleServicesResponse();
  
        center += request.getLatitude() + "," + request.getLongitude();
        markers += request.getLatitude() + "," + request.getLongitude();
  
        staticUrl += QUESTION_MARK + size + AMPERSAND + zoom + 
            AMPERSAND + center + AMPERSAND + markers + AMPERSAND + 
                mapType + AMPERSAND + SENSOR;
  
        byte[] imageBytes = null;
        try {
            imageBytes = HttpUtils.loadByteArrayImageFromHttp(staticUrl);
        } catch (IOException e) {
            System.err.println("IOException " + e.getMessage());
            response.setErrorDescription("An error has 
                occurred while creating the image");
        }
  
        response.setImage(imageBytes);
  
        return response;
    }

 
    public GoogleServicesResponse getImageFromAddress(
            ImageFromAddressRequest request) {

        System.out.println("getImageFromAddress");
  
        GoogleServicesResponse response = new GoogleServicesResponse();
  
        center += request.getAddress().replace(" ", "+");
  
        staticUrl += QUESTION_MARK + size + AMPERSAND + zoom +
            AMPERSAND + center + AMPERSAND + 
                mapType + AMPERSAND + SENSOR;
  
        byte[] imageBytes = null;
        try {
            imageBytes = HttpUtils.loadByteArrayImageFromHttp(staticUrl);
        } catch (IOException e) {
            System.err.println("IOException " + e.getMessage());
            response.setErrorDescription("An error has occurred 
                while creating the image");
        }
  
        response.setImage(imageBytes);
  
        return response;
    }

 
    public GoogleServicesResponse getImageRouteFromCoordinates(
            ImageRouteFromCoordinatesRequest request) {

        System.out.println("getImageRouteFromCoordinates");
        GoogleServicesResponse response = new GoogleServicesResponse();
  
        origin += request.getLatitudeOrg() + 
                        "," + request.getLongitudeOrg();
        destination += request.getLatitudeDst() + 
                        "," + request.getLongitudeDst();
    
        directionUrl += QUESTION_MARK + origin + AMPERSAND 
            + destination + AMPERSAND + SENSOR;
  
        try {
            response.setImage(getImageRoute());
        } catch (MalformedURLException e) {
            System.err.println("MalformedURLException " + e.getMessage());
            response.setErrorDescription("An error has occurred 
                while processing the request");
        } catch (IOException e) {
            System.err.println("IOException " + e.getMessage());
            response.setErrorDescription("An error has occurred 
                while creating the image containing the route");
        }
  
        return response;
    }

 
    public GoogleServicesResponse getImageRouteFromAddresses(
            ImageRouteFromAddressesRequest request) {

        GoogleServicesResponse response = new GoogleServicesResponse();
  
        System.out.println("getImageRouteFromAddresses");
  
        origin += request.getAddressOrg();
        destination += request.getAddressDst();
  
        for(int i = 0; i < request.getWaypoints().size(); i++) {
            if (i != 0) wayPoints += PIPE; 
            wayPoints += request.getWaypoints().get(i).replace(" ", "+");
        }
  
        directionUrl += QUESTION_MARK + origin + AMPERSAND + 
            destination + AMPERSAND + wayPoints + AMPERSAND + SENSOR;
    
        try {
            response.setImage(getImageRoute());
        } catch (MalformedURLException e) {
            System.err.println("MalformedURLException " + e.getMessage());
            response.setErrorDescription("An error has occurred
                    while processing the request");
        } catch (IOException e) {
            System.err.println("IOException " + e.getMessage());
            response.setErrorDescription("An error has occurred 
                    while creating the image containing the route");
        }
  
        return response;
    }
 
 
    private byte[] getImageRoute() 
            throws MalformedURLException, IOException {
  
        System.out.println(directionUrl);

        String xmlString = 
               HttpUtils.loadStringXmlFromHttp(directionUrl);  
  
        Document xmlDocumentResult = 
               XmlUtils.createXmlDocumentFromString(xmlString);
  
        String routeCoord = 
               XmlUtils.getRouteCoordinatesFromXml(xmlDocumentResult);
  
        staticUrl += QUESTION_MARK + size + AMPERSAND 
                  + path + routeCoord + AMPERSAND + SENSOR;
  
        byte[] imageBytes = null;
  
        imageBytes = HttpUtils.loadByteArrayImageFromHttp(staticUrl);

        return imageBytes;
    }

 
             /* GETTERS & SETTERS */
 
    public String getDirectionUrl() {
        return directionUrl;
    }


    public void setDirectionUrl(String directionUrl) {
        this.directionUrl = directionUrl;
    }


    public String getStaticUrl() {
        return staticUrl;
    }


    public void setStaticUrl(String staticUrl) {
        this.staticUrl = staticUrl;
    }


    public String getMapType() {
        return mapType;
    }


    public void setMapType(String mapType) {
        this.mapType = mapType;
    }


    public String getZoom() {
        return zoom;
    }


    public void setZoom(String zoom) {
        this.zoom = zoom;
    }


    public String getSize() {
        return size;
    }


    public void setSize(String size) {
        this.size = size;
    }


    public String getPath() {
        return path;
    }


    public void setPath(String path) {
        this.path = path;
    }


    public String getMarkers() {
        return markers;
    }


    public void setMarkers(String markers) {
        this.markers = markers;
    }


    public String getCenter() {
        return center;
    }


    public void setCenter(String center) {
        this.center = center;
    }


    public String getOrigin() {
        return origin;
    }


    public void setOrigin(String origin) {
        this.origin = origin;
    }


    public String getDestination() {
        return destination;
    }


    public void setDestination(String destination) {
        this.destination = destination;
    }


    public String getWayPoints() {
        return wayPoints;
    }


    public void setWayPoints(String wayPoints) {
        this.wayPoints = wayPoints;
    }
}


The Web Service Implementation bean has some constants and some instance variables with default values injected by the Spring context configuration file.
The implemented methods, after reading the request values make use of two classes, HttpUtils and XmlUtils, that I've implemented to call the Google Services using the HttpConnection, Stream, and XML related APIs to parse the response of the Google services.
These are the two utils classes that I am talking about:


The util class related to Http:
package com.faeddalberto.googlews.utils;

public class HttpUtils {

    public static String loadStringXmlFromHttp(
            String urlString) throws IOException, MalformedURLException {
  
        URL url = null;
        BufferedReader reader = null;
        StringBuilder stringBuilder = null;
  
        try {
            url = new URL(urlString);
 
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        
            // just want to do an HTTP GET here
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.connect();
   
            // read the output from the server
            reader = new BufferedReader(
                 new InputStreamReader(connection.getInputStream()));
            stringBuilder = new StringBuilder();
      
            String line = null;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line + "\n");
                System.out.println(line);
            }
      
        } finally {
        
            // close the reader; this can throw an exception too, so
            // wrap it in another try/catch block.
            if (reader != null)   {
                try {
                    reader.close();
                }  catch (IOException ioe) {
                    System.err.println("IOException " + ioe.getMessage());
                }
            }
        }
  
        return stringBuilder.toString();
    }
 
    public static byte[] loadByteArrayImageFromHttp(String urlString) throws IOException { 

        URL url = new URL(urlString); //Get an input stream for reading 

        HttpURLConnection hc = null;
        hc = (HttpURLConnection) url.openConnection();
        hc.setRequestMethod("GET");
        hc.setDoOutput(true);
        hc.connect();

        InputStream in = new BufferedInputStream(hc.getInputStream());
  
        try {
            ByteArrayOutputStream bout = new ByteArrayOutputStream(10000);
            int b;
            while ((b = in.read()) != -1) {
                bout.write(b);
            }
            
            return bout.toByteArray();
        } finally {
            in.close();
        }
    }

}



The util class related to XML:
package com.faeddalberto.googlews.utils;

public class XmlUtils {

    public static Document createXmlDocumentFromString(String result) {
  
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        InputSource source = new InputSource(new StringReader(result));
  
        Document document = null;
  
        try {
            document = factory.newDocumentBuilder().parse(source);
        } catch (SAXException e) {
            System.err.println("SAXException " + e.getMessage());
        } catch (IOException e) {
            System.err.println("IOException " + e.getMessage());
        } catch (ParserConfigurationException e) {
            System.err.println("ParserConfigurationException " + e.getMessage());
        }
   
        return document;
    }
 
    
    public static String getRouteCoordinatesFromXml(Document xmlDocumentResult) {
  
        String lat = null, lng = null, route = ""; 
  
        NodeList nList = xmlDocumentResult.getElementsByTagName("step");
  
        for (int temp = 0; temp < nList.getLength(); temp++) {
            Node nNode = nList.item(temp);
            if (nNode.getNodeType() == Node.ELEMENT_NODE) {

                Element eElement = (Element) nNode;

                System.out.println("LAT: " + getTagValue("lat", eElement));
                System.out.println("LONG: " + getTagValue("lng", eElement));
    
                lat = getTagValue("lat", eElement);
                lng = getTagValue("lng", eElement);
            }
   
            route += "|" + lat + "," + lng;
        }
  
        return route;
    }
 
    private static String getTagValue(String sTag, Element eElement) {
  
        NodeList nlList = 
             eElement.getElementsByTagName(sTag).item(0).getChildNodes();
   
        Node nValue = (Node) nlList.item(0);
  
        return nValue.getNodeValue();
    }
 
}


Next picture shows the browser with the resulting WSDL of the service calling http://127.0.0.1:8080/googlews/googleservices.wsdl. In the picture below we can only see the first part of the WSDL, containing the types associated with the service: 



The next thing I want to show you are the tests of the different web service operations and the images resulting from the calls. I have used jUnit to test the service methods:

1st method: Image from coordinates:
@Test
@DirtiesContext
public void getImageFromCoordinatesTest() throws IOException {
  
    GoogleServices services = 
               (GoogleServices) applicationContext.getBean("services");
  
    ImageFromCoordinatesRequest request = new ImageFromCoordinatesRequest();
    request.setLatitude(40.711614);
    request.setLongitude(-74.012318);
  
    String fileName = "lat " + request.getLatitude() + 
                      " lon " + request.getLongitude();
  
    GoogleServicesResponse response = services.getImageFromCoordinates(request); 
  
    Assert.assertNotNull(response.getImage());
  
    if (response.getImage() != null)
         createImageOnDisk(response.getImage(), fileName); 
    else System.out.println(response.getErrorDescription());
}




2nd method: Image from address:
@Test
@DirtiesContext
public void getImageFromAddressTest() throws IOException {
  
    GoogleServices services = 
         (GoogleServices) applicationContext.getBean("services");
  
    ImageFromAddressRequest request = new ImageFromAddressRequest();
    request.setAddress("Piccadilly Circus, London, UK");
  
    String fileName = request.getAddress().replace(',', ' ');
  
    GoogleServicesResponse response = services.getImageFromAddress(request);
  
    Assert.assertNotNull(response.getImage());
  
    if (response.getImage() != null) 
         createImageOnDisk(response.getImage(), fileName); 
    else System.out.println(response.getErrorDescription());
}



3rd method: Image route from coordinates origin and destination:
@Test
@DirtiesContext
public void getImageRouteFromCoordinatesTest() throws IOException {
 
    GoogleServices services = 
          (GoogleServices) applicationContext.getBean("services");
  
    ImageRouteFromCoordinatesRequest request =
            new ImageRouteFromCoordinatesRequest();
    request.setLatitudeOrg(37.4219720);
    request.setLongitudeOrg(-122.0841430);
    request.setLatitudeDst(37.4163228);
    request.setLongitudeDst(-122.0250403);
    
    String fileName = "latOrg " + request.getLatitudeOrg() + 
                      " lonOrg " + request.getLongitudeOrg() + 
                      "latDst " + request.getLatitudeDst() + 
                      " lonDst " + request.getLongitudeDst();
  
    GoogleServicesResponse response =
         services.getImageRouteFromCoordinates(request);
  
    Assert.assertNotNull(response.getImage());
  
    if (response.getImage() != null) 
        createImageOnDisk(response.getImage(), fileName); 
    else System.out.println(response.getErrorDescription());  
}



4th method: Image route from addresses origin and destination,  and eventually some waypoints:

@Test
@DirtiesContext
public void getImageRouteFromAddressesTest() throws IOException {
 
    GoogleServices services =
               (GoogleServices) applicationContext.getBean("services");
  
    ImageRouteFromAddressesRequest request =
          new ImageRouteFromAddressesRequest();
    request.setAddressOrg("Milano,MI");
    request.setAddressDst("Bologna,BO");
  
    List wayPoints = new ArrayList();
    wayPoints.add("Piacenza, PC");
    wayPoints.add("Modena, MO");
    request.setWaypoints(wayPoints);
  
    String fileName = request.getAddressOrg().replace(',', ' ') 
            + " - " + request.getAddressDst().replace(',', ' ');
  
    GoogleServicesResponse response =
               services.getImageRouteFromAddresses(request);
  
    Assert.assertNotNull(response.getImage());
  
    if (response.getImage() != null) 
        createImageOnDisk(response.getImage(), fileName); 
    else System.out.println(response.getErrorDescription());
}