Modularizing Crosscutting Concerns with Dynamic Proxy

Problem

As non-modularized crosscutting concerns will cause the code tangling and code scattering problems, you would like to seek a method to modularize them. However, they are often hard to modularize with the traditional object-oriented approach, as they span multiple modules of an application.

Solution

You can apply a design pattern called proxy to separate crosscutting concerns from core concerns. Proxy is one of the 23 GoF (Gang of Four) object-oriented design patterns, which belong to the “structural pattern” category. The principle of the proxy design pattern is to wrap an object with a proxy and use this proxy to substitute for the original object. Any calls that were made to the original object will go through the proxy first. Figure 5-2 illustrates the general idea of the proxy design pattern.

 

Figure 5-2. General idea of the proxy design pattern

The proxy object is responsible for deciding when and whether to forward method calls to the original object. In the meanwhile, the proxy can also perform additional tasks around each method call. So, the proxy would be a good place to implement the crosscutting concerns. In Java, there are two ways to implement the proxy design pattern. The traditional one is to write a static proxy in pure object-oriented style. Static proxy works by wrapping an object with a dedicated proxy to performadditional tasks around each method call. The dedication means you have to write a proxy class for each interface to be able to substitute for the original implementation, which is very inefficient in a large application with hundreds or thousands of components.

Another method is through the dynamic proxy support offered by JDK version 1.3 or higher. It supports creating a proxy dynamically for any object. The only restriction is that the object must implement at least one interface, and only the calls to the methods declared in the interfaces will go through the proxy. However, there’s another kind of proxy, CGLIB proxy, that doesn’t have this restriction. It can handle all the methods declared in a class even if it doesn’t implement any interface. Dynamic proxies are implemented with the Java Reflection API, so they can be used in a more general way than static proxies. For this reason, dynamic proxy is one of the core technologies used by Spring for its AOP implementation.

How It Works

A JDK dynamic proxy requires an invocation handler to handle method invocations. An invocation handler is simply a class that implements the following InvocationHandler interface:

 

package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

 

The only method declared in this interface is invoke(). It allows you to control the overall invocation process yourself. The first argument of the invoke() method is the proxy instance whose method was being invoked. The second argument is the method object whose type is java.lang.reflect.Method. It represents the current method being invoked. The last argument is an array of arguments for invoking the target method. Finally, you have to return a value as the current method invocation’s result.

Creating the Logging Proxy

By implementing the InvocationHandler interface, you can write an invocation handler that logs the method beginning and ending. You require a target calculator object to perform the actual calculation, which is passed in as a constructor argument.

 

package com.calculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CalculatorLoggingHandler implements InvocationHandler {
private Log log = LogFactory.getLog(this.getClass());
private Object target;
public CalculatorLoggingHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// Log the method beginning with the method name and arguments.

log.info("The method " + method.getName() + "() begins with "
+ Arrays.toString(args));
// Perform the actual calculation on the target calculator object by calling
// Method.invoke() and passing in the target object and method arguments.
Object result = method.invoke(target, args);
// Log the method ending with the returning result.
log.info("The method " + method.getName() + "() ends with " + result);
return result;
}
}

 

By using reflection, the invoke() method is general enough to handle all method calls of the two calculators. You can access the method name by calling Method.getName(), and you can access the arguments in an object array. To perform the actual calculation, you make a call to invoke() on the method object and pass in the target calculator object and method arguments. To create a JDK dynamic proxy instance with an invocation handler, you just make a call to the static method Proxy.newProxyInstance().

 

package com.calculator;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
ArithmeticCalculator arithmeticCalculatorImpl =
new ArithmeticCalculatorImpl();
ArithmeticCalculator arithmeticCalculator =
(ArithmeticCalculator) Proxy.newProxyInstance(
arithmeticCalculatorImpl.getClass().getClassLoader(),
arithmeticCalculatorImpl.getClass().getInterfaces(),
new CalculatorLoggingHandler(arithmeticCalculatorImpl));
...
}
}

 

The first argument of this method is the class loader to register this proxy. In most cases, you should define a proxy in the same class loader as the original class. The second argument consists of the interfaces for this proxy to implement. Only the calls to the methods declared in these interfaces will go through the proxy. Usually, you will proxy for all interfaces of the target class. The last argument is your invocation handler to handle the method invocation. By calling this method, you will get a proxy instance that was created by JDK dynamically. You can use it for calculation to have all method calls pass through the logging handler. For reuse purpose, you can encapsulate the proxy creation code in a static method of the handler class.

 

package com.calculator;
...
import java.lang.reflect.Proxy;
public class CalculatorLoggingHandler implements InvocationHandler {
...
public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new CalculatorLoggingHandler(target));
}
}

 

Now, the proxy creation code in the Main class is as simple as calling the static method.

 

package com.calculator;
public class Main {
public static void main(String[] args) {
ArithmeticCalculator arithmeticCalculatorImpl =
new ArithmeticCalculatorImpl();
ArithmeticCalculator arithmeticCalculator =
(ArithmeticCalculator) CalculatorLoggingHandler.createProxy(
arithmeticCalculatorImpl);
...
}
}

 

With this general logging invocation handler, you can also create a proxy for UnitCalculator dynamically.

package com.calculator;
public class Main {
public static void main(String[] args) {
...
UnitCalculator unitCalculatorImpl = new UnitCalculatorImpl();
UnitCalculator unitCalculator =
(UnitCalculator) CalculatorLoggingHandler.createProxy(
unitCalculatorImpl);
...
}
}

 

Figure 5-3 illustrates the implementation of the logging concern with the proxy design pattern.

 

Figure 5-3. Implementation of the logging concern with proxy

Creating the Validation Proxy

Similarly, you can write a validation handler as shown following. As a different method may have a different number of arguments, you have to loop the argument array to validate each method argument.

 

package com.calculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CalculatorValidationHandler implements InvocationHandler {
public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new CalculatorValidationHandler(target));
}
private Object target;
public CalculatorValidationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
for (Object arg : args) {
validate((Double) arg);
}
Object result = method.invoke(target, args);
return result;
}
private void validate(double a) {
if (a < 0) {
throw new IllegalArgumentException("Positive numbers only");
}
}
}

In the Main class, you can wrap the logging proxy by a validation proxy to form a proxy chain. Any calculator method calls will go through the validation proxy first and then the logging proxy. That means validation will be performed prior to logging. If you prefer the reverse order, you should use the logging proxy to wrap the validation proxy instead.

 

package com.calculator;
public class Main {
public static void main(String[] args) {
ArithmeticCalculator arithmeticCalculatorImpl =
new ArithmeticCalculatorImpl();
ArithmeticCalculator arithmeticCalculator =
(ArithmeticCalculator) CalculatorValidationHandler.createProxy(
CalculatorLoggingHandler.createProxy(
arithmeticCalculatorImpl));
...
UnitCalculator unitCalculatorImpl = new UnitCalculatorImpl();
UnitCalculator unitCalculator =
(UnitCalculator) CalculatorValidationHandler.createProxy(
CalculatorLoggingHandler.createProxy(
unitCalculatorImpl));
...
}
}

 

Figure 5-4 illustrates the implementation of both the validation and logging concerns with the proxy design pattern.

Figure 5-4. Implementation of both the validation and logging concerns with proxy

Keywords:

Filed Under: Spring

Problems with Non-Modularized Crosscutting Concerns

Why AOP is good

By definition, a crosscutting concern is a functionality that spans multiple modules of an application. This kind of concern is often hard to modularize with the traditional objectoriented approach. To understand crosscutting concerns, let’s start with a simple calculator example. First, you create two interfaces, ArithmeticCalculator and UnitCalculator, for arithmetic calculation and measurement unit conversion.

package com.calculator;
public interface ArithmeticCalculator {
public double add(double a, double b);
public double sub(double a, double b);
public double mul(double a, double b);
public double div(double a, double b);
}
package com.calculator;
public interface UnitCalculator {
public double kilogramToPound(double kilogram);
public double kilometerToMile(double kilometer);
}

 

Then you provide a simple implementation for each calculator interface. The println statements notify you of when these methods are executed.

package com.calculator;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
public double add(double a, double b) {
double result = a + b;
System.out.println(a + " + " + b + " = " + result);
return result;
}
public double sub(double a, double b) {
double result = a - b;
System.out.println(a + " - " + b + " = " + result);
return result;
}
public double mul(double a, double b) {
double result = a * b;
System.out.println(a + " * " + b + " = " + result);
return result;
}
public double div(double a, double b) {
double result = a / b;
System.out.println(a + " / " + b + " = " + result);
return result;
}
}
package com.calculator;
public class UnitCalculatorImpl implements UnitCalculator {
public double kilogramToPound(double kilogram) {
double pound = kilogram * 2.2;
System.out.println(kilogram + " kilogram = " + pound + " pound");
return pound;
}
public double kilometerToMile(double kilometer) {
double mile = kilometer * 0.62;
System.out.println(kilometer + " kilometer = " + mile + " mile");
return mile;
}
}

 

Tracing the Methods

A common requirement of most applications is to trace the activities that take place during program execution. For the Java platform, there are several logging implementations available for you to choose. However, if you would like your application to be independent of the logging implementation, you can make use of the Apache Commons Logging library. It provides abstract APIs that are implementation independent and allows you to switch between different implementations without modifying your code.

Note To use the Apache Commons Logging library, you have to include commons-logging.jar (locatedin the lib/jakarta-commons directory of the Spring installation) in your classpath.

For your calculators, you can log the beginning and ending of each method, as well as the method arguments and return values.

 

package com.calculator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
private Log log = LogFactory.getLog(this.getClass());
public double add(double a, double b) {
log.info("The method add() begins with " + a + ", " + b);
double result = a + b;
System.out.println(a + " + " + b + " = " + result);
log.info("The method add() ends with " + result);
return result;
}
public double sub(double a, double b) {
log.info("The method sub() begins with " + a + ", " + b);
double result = a - b;
System.out.println(a + " - " + b + " = " + result);
log.info("The method sub() ends with " + result);
return result;
}
public double mul(double a, double b) {
log.info("The method mul() begins with " + a + ", " + b);
double result = a * b;
System.out.println(a + " * " + b + " = " + result);
log.info("The method mul() ends with " + result);
return result;
}
public double div(double a, double b) {
log.info("The method div() begins with " + a + ", " + b);
double result = a / b;
System.out.println(a + " / " + b + " = " + result);
log.info("The method div() ends with " + result);
return result;
}
}
package com.calculator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class UnitCalculatorImpl implements UnitCalculator {
private Log log = LogFactory.getLog(this.getClass());
public double kilogramToPound(double kilogram) {
log.info("The method kilogramToPound() begins with " + kilogram);
double pound = kilogram * 2.2;
System.out.println(kilogram + " kilogram = " + pound + " pound");
log.info("The method kilogramToPound() ends with " + pound);
return pound;
}
public double kilometerToMile(double kilometer) {
log.info("The method kilometerToMile() begins with " + kilometer);
double mile = kilometer * 0.62;
System.out.println(kilometer + " kilometer = " + mile + " mile");
log.info("The method kilometerToMile() ends with " + mile);
return mile;
}
}

 

Now you are free to pick up a logging implementation supported by the Commons Logging library. Currently it mainly supports the Log4J library from Apache and the JDK Logging API (available for JDK 1.4 and higher versions). Of these, Log4J is the better choice, as it is more powerful and easier to configure.

Note To use the Log4J library, you have to include log4j-1.2.14.jar (located in the lib/log4j directory of the Spring installation) in your classpath. Once the Log4J library is detected in the classpath, Commons Logging will use it as the underlying logging implementation. You can configure the Log4J library through a properties file named log4j.properties in the root of the classpath. The following Log4J configuration file defines a log appender called stdout that will output log messages to the console in a format controlled by the specified pattern. For more information about logging patterns of Log4J, you can refer to the Log4J documentation.

 

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n
### set root logger level ###
log4j.rootLogger=error, stdout
### set application logger level ###
log4j.logger.com.calculator=info

 

Log4J supports six logging levels for you to set the urgency of your logging messages. Listed from highest to lowest, they are fatal, error, warn, info, debug, and trace. As specified in the preceding Log4J configuration file, the root (default) logging level for this application is error, which means that only logs for the error and fatal levels will be output by default. But for the com.calculator package and its subpackages, the logs for levels higher than info will also be output.

To test the basic functionalities and the logging configuration of these two calculators, you can write the Main class as follows:

 

package com.calculator;
public class Main {
public static void main(String[] args) {
ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl();
arithmeticCalculator.add(1, 2);
arithmeticCalculator.sub(4, 3);
arithmeticCalculator.mul(2, 3);
arithmeticCalculator.div(4, 2);
UnitCalculator unitCalculator = new UnitCalculatorImpl();
unitCalculator.kilogramToPound(10);
unitCalculator.kilometerToMile(5);
}
}

 

Validating the Arguments

Now let’s consider adding a restriction to your calculators. Suppose you would like your calculators to support positive numbers only. At the beginning of each method, you make calls to the validate() method to check if all the arguments are positive numbers. For any negative numbers, you throw an IllegalArgumentException.

 

package com.calculator;
...
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
...
public double add(double a, double b) {
validate(a);
validate(b);
...
}
public double sub(double a, double b) {
validate(a);
validate(b);
...
}
public double mul(double a, double b) {
validate(a);
validate(b);
...
}
public double div(double a, double b) {
validate(a);
validate(b);
...
}
private void validate(double a) {
if (a < 0) {
throw new IllegalArgumentException("Positive numbers only");
}
}
}
package com.calculator;
...
public class UnitCalculatorImpl implements UnitCalculator {
...
public double kilogramToPound(double kilogram) {
validate(kilogram);
...
}
public double kilometerToMile(double kilometer) {
validate(kilometer);
...
}
private void validate(double a) {
if (a < 0) {
throw new IllegalArgumentException("Positive numbers only");
}
}
}

 

Identifying the Problems

As you can see, the original calculator methods expand as you add more and more nonbusiness requirements, such as logging and validation. These systemwide requirements usually have to crosscut multiple modules, so they are called crosscutting concerns to distinguish them from the core business requirements, which are called the core concerns of a system.  Typical crosscutting concerns within an enterprise application include logging, validation, pooling, caching, authentication, and transaction. Figure 5-1 shows the crosscutting concerns in your calculator application.

Figure 5-1. Crosscutting concerns in the calculator application

However, with only classes and interfaces as programming elements, the traditional object-oriented approach cannot modularize crosscutting concerns well. Developers often have to mix them with core concerns in the same modules. As a result, these crosscutting concerns are spread out in different modules of an application and are thus not modularized.

There are two main problems caused by non-modularized crosscutting concerns. The first is code tangling. Like the preceding calculator methods, each of them has to handle multiple concerns as well as the core calculation logic at the same time. This will lead to poor code maintainability and reusability. For instance, the preceding calculator implementations would be hard to reuse in another application that has no logging requirement and can accept negative numbers as operands.

Another problem caused by non-modularized crosscutting concerns is code scattering.  For the logging requirement, you have to repeat the logging statements multiple times in multiple modules to fulfill a single requirement. Later, if the logging criteria change, you would have to modify all of the modules. Moreover, it is also hard to ensure that the logging requirement will be implemented consistently. If you have missed a logging statement somewhere, the overall system logging will be inconsistent.

For all these reasons, the calculators should concentrate on the core calculation logic only. Let’s separate the logging and validation concerns from them.

 

package com.calculator;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
public double add(double a, double b) {
double result = a + b;
System.out.println(a + " + " + b + " = " + result);
return result;
}
public double sub(double a, double b) {
double result = a - b;
System.out.println(a + " - " + b + " = " + result);
return result;
}
public double mul(double a, double b) {
double result = a * b;
System.out.println(a + " * " + b + " = " + result);
return result;
}
public double div(double a, double b) {
double result = a / b;
System.out.println(a + " / " + b + " = " + result);
return result;
}
}
package com.calculator;
public class UnitCalculatorImpl implements UnitCalculator {
public double kilogramToPound(double kilogram) {
double pound = kilogram * 2.2;
System.out.println(kilogram + " kilogram = " + pound + " pound");
return pound;
}
public double kilometerToMile(double kilometer) {
double mile = kilometer * 0.62;
System.out.println(kilometer + " kilometer = " + mile + " mile");
return mile;
}
}

 

 

Keywords:

Filed Under: Spring

Intro to AOP

 

Besides the IoC container, another core module of the Spring framework is its AOP framework.  Currently, there are many AOP frameworks on the market implemented for different purposes and based on different technologies, but only the following three open source AOP frameworks have entered the mainstream:

• AspectJ, merged with AspectWerkz since version 5 www.eclipse.org/aspectj/

• JBoss AOP, a subproject of the JBoss appl. server labs.jboss.com/jbossaop/

• Spring AOP, as part of the Spring framework www.springframework.org/

Among them, AspectJ is the most complete and popular AOP framework in the Java community. By comparison, Spring AOP is not a competitor of AspectJ to provide another complete AOP implementation. Its purpose is only to provide an AOP solution that can consistently integrate with its IoC container. In fact, Spring AOP will only handle crosscutting concerns for the beans declared in its IoC container.

Keywords:

Filed Under: Spring

Standard Directory Layout (Maven)

 

Good info here.

 

Having a common directory layout would allow for users familiar with one project to immediately feel at home in another project. The advantages are analogous to adopting a site-wide look-and-feel.

Please try to conform to this structure as much as possible:

 Directory  Description
 src/main/java  Application/Library sources
 src/main/resources  Application/Library resources
 src/main/filters  Resource filter files
 src/main/assembly  Assembly descriptors
 src/main/config  Configuration files
 src/main/webapp  Web application sources
 src/test/java  Test sources
 src/test/resources  Test resources
 src/test/config  Configuration files
 src/test/filters  Usage resource filter files
 src/usage/java  Usage sources
 src/usage/resources  Usage resources
 src/usage/config  Usage Configuration files
 src/site  Site
 LICENSE.txt  Project's license
 README.txt  Project's readme

 

The structure is loosly based on the MAVEN structure at: http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html

Another good site is: http://cvs.peopleware.be/training/maven/maven2/standardDirLayout.html

artifactId/
project directory
|- .cvsignore
contains target, profiles.xml
|- pom.xml
POM
|- profiles.xml
local, user and project dependent profile definitions; this should not be version controlled
|- LICENSE.txt
license of the project
|- README.txt
welcome to the reader
|- src/
original material; this should be version controlled
||- main/
the original material for the artifact
|||- java/
root of main Java source; wil be compiled into target/classes
|||- resources/
main Java resources; will be copied into target/classes
|||- webapp/
|||- WEB-INF/
|||`- web.xml
||`- index.jsp
web application with standard web application structure
|||- assembly/
||`- dep.xml
assembly descriptor for maven-assembly-plugin
|||- filters/
resource filter properties files for main Java resources
|||- config/
configuration files for the artifact
|||- bash/
|||- groovy/
|||- prolog/
||`- sql/
sources in other technologies for the artifact
||- site/
project documentation in different formates; mvn site will produce a project website in target/site based on this material and structure (Doxia)
|||- apt/
||||- format.apt
|||`- index.apt
documentation in APT format (wiki-like HTML generation)
 
 
|||- fml/
|||`- faq.fml 
documentation in FML format (XML based FAQ format)
 
 
|||- resources/
||||- css/
||||- img/
|||`- js/
site resources; will be copied into target/site as-is
 
 
|||- site.xml 
site descriptor: description of site structure; this will generate menus 
||`- xdoc/
||`- xdoc.xml 
documentation in Xdoc format (XML based HTML generation; maven 1 legacy)
|`- test/
original material to test the artifact
||- java/
root of Java source for testing the artifact; usually JUnit test classes; will be compiled into target/test-classes
||- resources/ 
resources for testing the artifact; will be copied into target/test-classes
||- filters/ 
resource filter properties files for resources for testing the artifact
||- perl/
||- haskell/
|`- python/
sources in other technologies for testing the artifact
 
 
 
`- target/
generated material; this should not be under version control
|- artifactId-version.jar
generated artifact
|- classes/ 
result of compilation of src/main/java and copy of src/main/resources
|- exported-pom.xml
consolidated POM
|- javadoc/
javadoc of src/main/java
|- site/
project site generated by mvn site
|- surefire-reports/
test reports 
|- test-classes/
result of compilation of src/test/java and copy of src/test/resources
`- announcement/
`- announcement.vm
org.codehaus.mojo:changelog-maven-plugin generates announcement mail here

 

 

Keywords:

Filed Under: Infrastructure · Java

Loading External Resources

Problem

Sometimes your application may need to read external resources (e.g., text files, XML files, properties file, or image files) from different locations (e.g., a file system, classpath, or URL). Usually, you have to deal with different APIs for loading resources from different locations.

Solution

Spring’s resource loader provides a unified getResource() method for you to retrieve an external resource by a resource path. You can specify different prefixes for this path to load resources from different locations. To load a resource from a file system, you use the file prefix. To load a resource from the classpath, you use the classpath prefix. You may also specify a URL in this resource path. Resource is a general interface in Spring for representing an external resource. Spring provides several implementations for the Resource interface, as shown below. The resourceloader’s getResource() method will decide which Resource implementation to instantiate according to the resource path.

 

Figure 4-1. Common implementations of the Resource interface

How It Works

Suppose you would like to display a banner at the startup of your shop application. The banner is made up of the following characters and stored in a text file called banner.txt. This file can be put in the current path of your application.

 

 

***********************
* Welcome to My Shop! *
***********************

 

Next you have to write the BannerLoader class to load the banner and output it to the console. As it requires access to a resource loader for loading the resource, it has to implement either the ApplicationContextAware interface or the ResourceLoaderAware interface.

 

package com.apress.springrecipes.shop;
...
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
public class BannerLoader implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void showBanner() throws IOException {
Resource banner = resourceLoader.getResource("file:banner.txt");
InputStream in = banner.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while (true) {
String line = reader.readLine();
if (line == null)
break;
System.out.println(line);
}
reader.close();
}
}

 

By calling the getResource() method from the application context, you can retrieve an external resource specified by a resource path. As your banner file is located in the file system, the resource path should start with the file prefix. You can call the getInputStream() method to retrieve the input stream for this resource. Then you read the file contents line by line with BufferedReader and output them to the console.  Finally, you declare a BannerLoader instance in the bean configuration file to display the banner. As you would like to show the banner at startup, you specify the showBanner() method as the initialization method.

 

<bean id="bannerLoader"
class="com.apress.springrecipes.shop.BannerLoader"
init-method="showBanner" />

 

Resource Prefixes

The previous resource path specifies a resource in the relative path of the file system. You can specify an absolute path as well. file:c:/shop/banner.txt When your resource is located in the classpath, you have to use the classpath prefix. If there’s no path information presented, it will be loaded from the root of the classpath. classpath:banner.txt If the resource is located in a particular package, you can specify the absolute path from the classpath root. classpath:com/apress/springrecipes/shop/banner.txt Besides a file system path or the classpath, a resource can also be loaded by specifying a URL. http://localhost/shop/banner.txt  If there’s no prefix presented in the resource path, the resource will be loaded from a location according to the application context. For FileSystemXmlApplicationContext, the resource will be loaded from the file system. For ClassPathXmlApplicationContext, it will be loaded from the classpath.

Injecting Resources

In addition to calling the getResource() method to load a resource explicitly, you can inject it by using a setter method:

 

package com.apress.springrecipes.shop;
...
import org.springframework.core.io.Resource;
public class BannerLoader {

private Resource banner;
public void setBanner(Resource banner) {
this.banner = banner;
}
public void showBanner() throws IOException {
InputStream in = banner.getInputStream();
...
}
}

 

In the bean configuration, you can simply specify the resource path for this Resource property. Spring will use the preregistered property editor ResourceEditor to convert it into a Resource object before injecting it into your bean.

 

<bean id="bannerLoader"
class="com.apress.springrecipes.shop.BannerLoader"
init-method="showBanner">
<property name="banner">
<value>classpath:com/apress/springrecipes/shop/banner.txt</value>
</property>
</bean>

 

 

Keywords:

Filed Under: Spring

Creating Custom Property Editors

Problem

In addition to registering the built-in property editors, you may want to write your own custom property editors for converting your custom data types.

Solution

You can write custom property editors by implementing the java.beans.PropertyEditor interface or extending the convenient support class java.beans.PropertyEditorSupport.

How It Works

For example, let’s write a property editor for the Product class. You can design the string representation of a product as three parts, which are the concrete class name, the product name, and the price. Each part is separated by a comma. Then you can write the following ProductEditor class for converting them:

 

package com.shop;
import java.beans.PropertyEditorSupport;
public class ProductEditor extends PropertyEditorSupport {
public String getAsText() {
Product product = (Product) getValue();
return product.getClass().getName() + "," + product.getName() + "," + product.getPrice();
}
public void setAsText(String text) throws IllegalArgumentException {
String[] parts = text.split(",");
try {
Product product = (Product) Class.forName(parts[0]).newInstance();
product.setName(parts[1]);
product.setPrice(Double.parseDouble(parts[2]));
setValue(product);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
}

 

The getAsText() method converts a property into a string value, while the setAsText() method converts a string back into a property. The property value is retrieved and set by calling the getValue() and setValue() methods. Next you have to register your custom editor in a CustomEditorConfigurer instance before it can be used. Registration is the same as for the built-in editors. Now you can specify a product in text format for any property whose type is Product.

<beans ...>
...
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
...
<entry key="com.shop.Product">
<bean class="com.shop.ProductEditor" />
</entry>
</map>
</property>
</bean>
<bean id="productRanking"
class="com.shop.ProductRanking">
<property name="bestSeller">
<value>com.shop.Disc,CD-RW,1.5</value>
</property>
...
</bean>
</beans>

 

In fact, the JavaBeans API will automatically search a property editor for a class. For a property editor to be searched correctly, it must be located in the same package as the target class, and the name must be the target class name with Editor as its suffix. If your property editor is provided in this convention, such as in the preceding ProductEditor, there’s no need to register it again in the Spring IoC container.

Keywords:

Filed Under: Spring

Registering Property Editors in Spring

I could not get this to work... 

Problem

A property editor is a feature of the JavaBeans API for converting property values to and from text values. Each property editor is designed for a certain type of property only. You may wish to employ property editors to simplify your bean configurations.

Solution

The Spring IoC container supports using property editors to help with bean configurations.  For example, with a property editor for the java.net.URL type, you can specify a URL string for a property of the URL type. Spring will automatically convert the URL string into a URL object and inject it into your property. Spring comes with several property editors for converting bean properties of common types.

Typically, you should register a property editor in the Spring IoC container before it can be used. The CustomEditorConfigurer is implemented as a bean factory post processor for you to register your custom property editors before any of the beans get instantiated.

How It Works

As an example, suppose you would like your product ranking to be based on sales for a particular period. For this change, you add the fromDate and toDate properties to your ProductRanking class.

package com.apress.springrecipes.shop;
...
public class ProductRanking {
private Product bestSeller;
private Date fromDate;
private Date toDate;
// Getters and Setters
...
}

 

To specify the value for a java.util.Date property in a Java program, you can convert it from a date string of particular pattern with the help of the DateFormat.parse() method.

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
productRanking.setFromDate(dateFormat.parse("2007-09-01"));
productRanking.setToDate(dateFormat.parse("2007-09-30"));

 

To write the equivalent bean configuration in Spring, you first declare a dateFormat bean with the pattern configured. As the parse() method is called for converting the date strings into date objects, you can consider it as an instance factory method to create the date beans.

 

<beans ...>
...
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
<bean id="productRanking"
class="com.apress.springrecipes.shop.ProductRanking">
<property name="bestSeller">
<bean class="com.apress.springrecipes.shop.Disc">
<property name="name" value="CD-RW" />
<property name="price" value="1.5" />
</bean>
</property>
<property name="fromDate">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2007-09-01" />
</bean>
</property>
<property name="toDate">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2007-09-30" />
</bean>
</property>
</bean>
</beans>

 

As you can see, the preceding configuration is too complicated for setting date properties.  Actually, the Spring IoC container is able to convert the text values for your properties by using property editors. The CustomDateEditor class that comes with Spring is for converting date strings into java.util.Date properties. First, you have to declare an instance of it in the bean configuration file.

 

<beans ...>
...
<bean id="dateEditor"
class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
</beans>

 

This editor requires a DateFormat object as the first constructor argument. The second argument indicates whether this editor allows empty values.  Next you have to register this property editor in a CustomEditorConfigurer instance so that Spring can convert properties whose type is java.util.Date. Now you can specify a date value in text format for any java.util.Date properties:

 

<beans ...>
...
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<ref local="dateEditor" />
</entry>
</map>
</property>
</bean>
<bean id="productRanking"
class="com.apress.springrecipes.shop.ProductRanking">
<property name="bestSeller">
<bean class="com.apress.springrecipes.shop.Disc">
<property name="name" value="CD-RW" />
<property name="price" value="1.5" />
</bean>
</property>
<property name="fromDate" value="2007-09-01" />
<property name="toDate" value="2007-09-30" />
</bean>
</beans>

 

You can test whether your CustomDateEditor configuration works with the following Main class:

 

package com.apress.springrecipes.shop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
...
ProductRanking productRanking =
(ProductRanking) context.getBean("productRanking");
System.out.println("Product ranking from " + productRanking.getFromDate() + " to " + productRanking.getToDate());
}
}

 

In addition to CustomDateEditor, Spring comes with several property editors for converting common data types, such as CustomNumberEditor, ClassEditor, FileEditor, LocaleEditor, StringArrayPropertyEditor, and URLEditor. Among them, ClassEditor, FileEditor, LocaleEditor, and URLEditor are preregistered by Spring, so you don’t need to register them again. For more information on using these editors, you can consult the javadoc of these classes in the org.springframework.beans.propertyeditors package.

Keywords:

Filed Under: Spring

Communicating with Application Events (Listener)

 

Problem

In the typical communication model between components, the sender has to locate the receiver to call a method on it. In this case, the sender component must be aware of the receiver component. This kind of communication is direct and simple, but the sender and receiver components are tightly coupled.

When using an IoC container, your components can communicate by interface rather than by implementation. This communication model can help reduce coupling. However, it is only efficient when a sender component has to communicate with one receiver. When a sender needs to communicate with multiple receivers, it has to call the receivers one by one.

Solution

Spring’s application context supports event-based communication between its beans. In the event-based communication model, the sender component just publishes an event without knowing who the receiver will be. Actually, there may be more than one receiver component.  Also, the receiver needn’t know who is publishing the event. It can listen to multiple events from different senders at the same time. In this way, the sender and receiver components are loosely coupled. 

In Spring, all event classes must extend the ApplicationEvent class. Then any bean can publish an event by calling an application event publisher’s publishEvent() method. For a bean to listen to certain events, it must implement the ApplicationListener interface and handle the events in the onApplicationEvent() method. Actually, Spring will notify a listener of all events, so you must filter the events by yourself.

How It Works

Defining Events

The first step of enabling event-based communication is to define the event. Suppose you would like your cashier bean to publish a CheckoutEvent after the shopping cart has been checked out. This event includes two properties: the payment amount and the checkout time.  In Spring, all events must extend the abstract class ApplicationEvent and pass the event source as a constructor argument.

 

package com.shop;
...
import org.springframework.context.ApplicationEvent;
public class CheckoutEvent extends ApplicationEvent {
private double amount;
private Date time;
public CheckoutEvent(Object source, double amount, Date time) {
super(source);
this.amount = amount;
this.time = time;
}
public double getAmount() {
return amount;
}
public Date getTime() {
return time;
}
}

 

Publishing Events

To publish an event, you just create an event instance and make a call to the publishEvent() method of an application event publisher, which can be accessed by implementing the ApplicationEventPublisherAware interface.

 

package com.shop;
...
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
public class Cashier implements BeanNameAware, MessageSourceAware,
ApplicationEventPublisherAware, StorageConfig {
...
private ApplicationEventPublisher applicationEventPublisher;
...
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void checkout(ShoppingCart cart) throws IOException {
...
CheckoutEvent event = new CheckoutEvent(this, total, new Date());
applicationEventPublisher.publishEvent(event);
}
}

 

Listening to Events

Any bean defined in the application context that implements the ApplicationListener interface will be notified of all events. So in the onApplicationEvent() method, you have to filter the events that your listener wants to handle. In the following listener, suppose you would like to send an e-mail to the customer notifying them about the checkout.

package com.shop;
...
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class CheckoutListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof CheckoutEvent) {
double amount = ((CheckoutEvent) event).getAmount();
Date time = ((CheckoutEvent) event).getTime();
// Do anything you like with the checkout amount and time
System.out.println("Checkout event [" + amount + ", " + time + "]");
}
}
}

 

Next, you have to register this listener in the application context to listen for all events.  The registration is as simple as declaring a bean instance of this listener. The application context will recognize the beans that implement the ApplicationListener interface and notify them of each event.

<beans ...>
...
<bean class="com.shop.CheckoutListener" />
...
</beans>

 

Finally, notice that the application context itself will also publish container events such as ContextClosedEvent, ContextRefreshedEvent, and RequestHandledEvent. If any of your beans want to be notified of these events, they can implement the ApplicationListener interface.

Keywords:

Filed Under: Spring

Resolving Text Messages (message Properties)

 

Problem

For an application to support internationalization (I18N for short, as there are 18 characters between the first character, i, and the last character, n), it requires the capability of resolving text messages for different locales.

Solution

Spring’s application context is able to resolve text messages for a target locale by their keys. Typically, the messages for one locale should be stored in one separate properties file. This properties file is called a resource bundle.

MessageSource is an interface that defines several methods for resolving messages. The ApplicationContext interface extends this interface so that all application contexts are able to resolve text messages. An application context delegates the message resolution to a bean with the exact name messageSource. ResourceBundleMessageSource is the most common MessageSource implementation that resolves messages from resource bundles for different locales.

How It Works

As an example, you can create the following resource bundle, messages_en_US.properties, for the English language in the United States. Resource bundles will be loaded from the root of the classpath.

alert.checkout=A shopping cart has been checked out.

 

To resolve messages from resource bundles, you use ResourceBundleMessageSource as your MessageSource implementation. This bean’s name must be set to messageSource for the application context to detect it. You have to specify the base name of the resource bundles for ResourceBundleMessageSource.

<beans ...>
...
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>messages</value>
</property>
</bean>
</beans>

 

For this MessageSource definition, if you look up a text message for the United States locale, whose preferred language is English, the resource bundle messages_en_US.properties, which matches both the language and country, will be considered first. If there’s no such resource bundle or the message can’t be found, the one messages_en.properties that matches the language only will be considered. If this resource bundle still can’t be found, the default messages.properties for all locales will be chosen finally. For more information on resource bundle loading, you can refer to the javadoc of the java.util.ResourceBundle class. Now you can ask the application context to resolve a message by the getMessage() method. The first argument is the key corresponding to the message and the third is the target locale.

package com.shop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Main {
public static void main(String[] args) throws Exception {
ApplicationContext context =
new FileSystemXmlApplicationContext("beans.xml");
...
String alert = context.getMessage("alert.checkout", null, Locale.US);
System.out.println(alert);
}
}

 

The second argument of the getMessage() method is an array of message parameters. In the text message, you can define multiple parameters by index:

 

alert.checkout=A shopping cart costing {0} dollars has been checked out at {1}.

 

You have to pass in an object array to fill in the message parameters. The elements in this array will be converted into strings before filling in the parameters.

 

package com.shop;
...
public class Main {
public static void main(String[] args) throws Exception {
...
String alert = context.getMessage("alert.checkout", new Object[] { 4, new Date() }, Locale.US);
System.out.println(alert);
}
}

 

In the Main class, you can resolve text messages because you can access the application context directly. But for a bean to resolve text messages, it has to implement either the ApplicationContextAware interface or the MessageSourceAware interface. Now you can delete the message resolution from the Main class.

package com.shop;
...
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
public class Cashier implements BeanNameAware, MessageSourceAware,
StorageConfig {
...
private MessageSource messageSource;
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public void checkout(ShoppingCart cart) throws IOException {
...
String alert = messageSource.getMessage("alert.checkout",
new Object[] { total, new Date() }, Locale.US);
System.out.println(alert);
}
}

 

 

Keywords:

Filed Under: Spring

Externalizing Bean Configurations (properties)

 

Problem

When configuring beans in the configuration file, you must remember that it’s not a good practice to mix deployment details, such as the file path, server address, username, and password, with your bean configurations. Usually, the bean configurations are written by application developers while the deployment details are matters for the deployers or system administrators.

Solution

Spring comes with a bean factory post processor called PropertyPlaceholderConfigurer for you to externalize part of the bean configurations into a properties file. You can use variables of the form ${var} in your bean configuration file and PropertyPlaceholderConfigurer will load the properties from a properties file and use them to replace the variables.

A bean factory post processor differs from a bean post processor in that its target is the IoC container—either the bean factory or the application context—not the bean instances. It will take effect on the IoC container after it loads the bean configurations but before any of the bean instances are created. The typical usage of a bean factory post processor is to alter the bean configurations before the beans are instantiated. Spring comes with several bean factory post processors for you to use. In practice, you seldom need to write your own bean factory post processors.

How It Works

Previously, you specified the logging path for a cashier in the bean configuration file. It is not a good practice to mix such deployment details with your bean configurations. A better approach is to extract the deployment details into a properties file, such as config.properties, in the root of the classpath. Then define the logging path in this file. cashier.path=c:/cashier Now you can use variables of the form ${var} in your bean configuration file. To load the external properties from a properties file and use them to replace the variables, you have to register the bean factory post processor PropertyPlaceholderConfigurer in your application context. You can specify either one properties file in the location property or multiple properties files in the locations property.

 

<beans ...>
...
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>config.properties</value>
</property>
</bean>
<bean id="cashier1" class="com.shop.Cashier">
<property name="path" value="${cashier.path}" />
</bean>
</beans>

 

Implemented as a bean factory post processor, PropertyPlaceholderConfigurer will replace the variables in your bean configuration file with the external properties before your beans get instantiated. In Spring 2.5, the registration of PropertyPlaceholderConfigurer can be simply through the <context:property-placeholder> element.

 

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:property-placeholder location="config.properties" />
...
</beans>

 

 

Keywords:

Filed Under: Spring

TextBox widget example - adding any formatted HTML code to the widget.

Comment List

  • None

Month List