decouplingcs decoupling case studyriad.usk.pk.edu.pl/~pzabawa/en/files/ei/decouplingcs.pdf · 1...
TRANSCRIPT
1
Piotr Zabawa, PhD. Eng. Krakow, 10th
of December, 2011
Software Engineering Section
Faculty of Physics, Mathematics and Computer Science
Cracow University of Technology
e-mail: [email protected]
www: http://www.pk.edu.pl/~pzabawa/en
www: http://www.pk.edu.pl/~pzabawa/en/business.html
DecouplingCS
Decoupling Case Study
This case study explains step-by-step the concept of decoupling. It recognizes problems characteristic
for each implementation of decoupling and moves forward making the decoupling better. This case
study is composed of several projects:
1. JavaSEDecouplingTCS - investigation of decoupling barriers in case of Java Standard Edition
2. AspectJDecouplingTCS - decoupling based on application of AOP
3. SeamDecouplingTCS - possible solutions of decoupling problem offered by application of
Seam Framework
4. SpringDecouplingTCS - possible solutions of decoupling problem offered by application of
Spring Framework
5. *DecouplingTCS_soa - application of SOA for each framework for technology decoupling
All projects are implemented and ready for execution and are published in the form of *.zip files.
Each zip file may consist of many projects.
The case-study scenario is presented below.
2
SOA
JavaEE
AspectJ
SpringSeam
JavaSE
JavaSEDecouplingTCS_01_simple
JavaSEDecouplingTCS_02_cmd
JavaSEDecouplingTCS_03_service
JavaSEDecouplingTCS_04_jinterface
JavaSEDecouplingTCS_05_jfactory
SpringDecouplingTCS_01_factory
SpringDecouplingTCS_02_diprops
SpringDecouplingTCS_03_dixml
SpringDecouplingTCS_04_dixmlctorarg
SpringDecouplingTCS_06_ws
SpringDecouplingTCS_07_soa
SpringDecouplingTCS_05_annot
SeamDecouplingTCS_01_factory
SeamDecouplingTCS_02_diprops
SeamDecouplingTCS_03_dixml
SeamDecouplingTCS_04_dixmlctorarg
SeamDecouplingTCS_06_ws
SeamDecouplingTCS_07_soa
SeamDecouplingTCS_05_annot
AspectJDecouplingTCS_04a_simple
AspectJDecouplingTCS_05_factory
The idea of the whole case-study is to find a good solution of decoupling service provider from
service consumer. That means that any changes introduced to one of them must not involve any
changes in the other.
3
JavaSEDecouplingTCS
JavaSEDecouplingTCS_01_simple
Characteristics:
package pl.edu.pk.ip.decoupling.simple;
public class HelloWorldSimple {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Disadvantages:
Any changes introduced into service provider (a message to be printed) influence the whole
source code and result in recompilation of the whole source code. No distinction between
service provider and service consumer.
Opportunities:
Introduction of flexibility in message changing.
JavaSEDecouplingTCS_02_cmd
Characteristics:
package pl.edu.pk.ip.decoupling.cmd;
public class HelloWorldCmd {
public static void main(String[] args) {
if (args.length > 0) {
System.out.println(args[0]);
} else {
System.out.println("Hello World!");
}
}
}
Improvements:
Message can be changed runtime without the need of source code recompilation.
Disadvantages:
Hardcoded way of printing (println), no way of different rendering or to printing to different
target without recompilation. Printing is directly associated to obtaining the message. Still no
distinction between service provider and service consumer.
Opportunities:
Separation of obtaining message logic (service provider) from rendering message logic
(service consumer). This way we can change any logic without affecting the other.
JavaSEDecouplingTCS_03_service
HelloWorldSimple.java
HelloWorldCmd.java
4
Characteristics:
package pl.edu.pk.ip.decoupling.service;
public class HelloWorldServiceProvider {
public String getMessage() {
return "Hello World!";
}
}
package pl.edu.pk.ip.decoupling.service;
public class HelloWorldServiceConsumer {
private HelloWorldServiceProvider messageProvider = null;
public void setMessageProvider(HelloWorldServiceProvider provider) {
this.messageProvider = provider;
}
public void render() {
String message = messageProvider.getMessage();
System.out.println(message);
}
}
package pl.edu.pk.ip.decoupling.service;
public class HelloWorldBusinessProcess {
public static void main(String[] args) {
HelloWorldServiceConsumer mr = new HelloWorldServiceConsumer();
HelloWorldServiceProvider mp = new HelloWorldServiceProvider();
mr.setMessageProvider(mp);
mr.render();
}
}
Improvements:
Separation of service provider and service consumer logic was achieved. Introduction of
changes into one of them does not affect the other.
Disadvantages:
A particular message provider is hardcoded into message consumer. So, switching to other
service provider without changing in the source code of service consumer is limited.
Opportunities:
Introduction of services will eliminate the problem of switching to other service provider.
JavaSEDecouplingTCS_04_jinterface
Characteristics:
package pl.edu.pk.ip.decoupling.jinterface;
public interface ServiceProviderInterface {
public String getMessage();
}
HelloWorldServiceProvider.java
HelloWorldServiceConsumer.java
HelloWorldBusinessProcess.java
ServiceProviderInterface.java
5
package pl.edu.pk.ip.decoupling.jinterface;
public class ServiceProviderImplementation implements ServiceProviderInterface {
public String getMessage() {
return "Hello World!";
}
}
package pl.edu.pk.ip.decoupling.jinterface;
public interface ServiceConsumerInterface {
public void render();
public void setMessageProvider(ServiceProviderInterface provider);
public ServiceProviderInterface getMessageProvider();
}
package pl.edu.pk.ip.decoupling.jinterface;
public class ServiceConsumerImplementation implements ServiceConsumerInterface {
private ServiceProviderInterface messageProvider = null;
public void render() {
if (messageProvider == null) {
throw new RuntimeException(
"You must set the property messageProvider of class:"
+ ServiceConsumerInterface.class.getName());
}
System.out.println(messageProvider.getMessage());
}
public void setMessageProvider(ServiceProviderInterface provider) {
this.messageProvider = provider;
}
public ServiceProviderInterface getMessageProvider() {
return this.messageProvider;
}
}
package pl.edu.pk.ip.decoupling.jinterface;
public class BusinessProcess {
public static void main(String[] args) {
ServiceConsumerInterface mr = new ServiceConsumerImplementation();
ServiceProviderInterface mp = new ServiceProviderImplementation();
mr.setMessageProvider(mp);
mr.render();
}
}
Improvements:
Message provider may change without impact to message consumer.
Disadvantages:
Both provider and consumer may change independently one to another. But these changes
have strong impact onto business logic (the launcher).
Opportunities:
ServiceProviderImplementation.java
ServiceConsumerInterface.java
ServiceConsumerImplementation.java
BusinessProcess.java
6
The responsibility of creation of objects of the right classes may be delegated to the factory
design pattern.
JavaSEDecouplingTCS_05_jfactory
Characteristics:
package pl.edu.pk.ip.decoupling.jfactory;
import java.io.FileInputStream;
import java.util.Properties;
public class DecouplingFactory {
private static DecouplingFactory instance = null;
private Properties props = null;
private ServiceConsumerInterface renderer = null;
private ServiceProviderInterface provider = null;
private DecouplingFactory() {
props = new Properties();
try {
props.load(new FileInputStream("factory.properties"));
String rendererClass = props.getProperty("consumer.class");
String providerClass = props.getProperty("provider.class");
renderer = (ServiceConsumerInterface)
Class.forName(rendererClass).newInstance();
provider = (ServiceProviderInterface)
Class.forName(providerClass).newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
}
static {
instance = new DecouplingFactory();
}
public static DecouplingFactory getInstance() {
return instance;
}
public ServiceConsumerInterface getMessageRenderer() {
return renderer;
}
public ServiceProviderInterface getMessageProvider() {
return provider;
}
}
consumer.class=pl.edu.pk.ip.decoupling.jfactory.ServiceConsumerImplementation
provider.class=pl.edu.pk.ip.decoupling.jfactory.ServiceProviderImplementation
package pl.edu.pk.ip.decoupling.jfactory;
public class BusinessProcess {
public static void main(String[] args) {
ServiceConsumerInterface mr =
DecouplingFactory.getInstance().getMessageRenderer();
ServiceProviderInterface mp =
DecouplingFactory.getInstance().getMessageProvider();
mr.setMessageProvider(mp);
mr.render();
}
}
DecouplingFactory.java
factory.properties
BusinessProcess.java
7
Improvements:
No any change must be done in source code to change service provider. It is enough to
change items in property file.
Disadvantages:
In order to achieve this level of decoupling the glue code is needed. It consists of the factory
implementation as well as association of message provider into message consumer. This is
called wiring.
Opportunities:
Wiring could be handled by a framework. In fact it is supported by both Seam and Spring
Java EE frameworks by their built-in factories and mechanism for associating objects.
AspectJDecouplingTCS
SeamDecouplingTCS
SpringDecouplingTCS
SpringDecouplingTCS_01_factory
Characteristics:
package pl.edu.pk.ip.decoupling.springfactory;
import java.io.FileInputStream;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
public class BusinessProcess {
public static void main(String[] args) throws Exception {
BeanFactory factory = getBeanFactory();
ServiceConsumerInterface mr = (ServiceConsumerInterface)
factory.getBean("consumer");
ServiceProviderInterface mp = (ServiceProviderInterface)
factory.getBean("provider");
mr.setMessageProvider(mp);
mr.render();
}
private static BeanFactory getBeanFactory() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader rdr = new
PropertiesBeanDefinitionReader(factory);
Properties props = new Properties();
props.load(new FileInputStream("factory.properties"));
rdr.registerBeanDefinitions(props);
return factory;
}
}
BusinessProcess.java
8
consumer.(class)=pl.edu.pk.ip.decoupling.springfactory.ServiceConsumerImplementation
provider.(class)=pl.edu.pk.ip.decoupling.springfactory.ServiceProviderImplementation
Improvements:
User implemented glue code was limited due to the usage of Spring built-in low-level internal
factory - the Spring framework implementation of factory method design pattern.
Disadvantages:
There is still a glue code in business process which is responsible for creation of service
provider, the service of which is not directly used from business process. Creation of this
object is necessary for passing it to the service consumer in order to configure the last one.
Opportunities:
The wiring of service provider into service consumer can be eliminated from the source code
to limit the amount of work business process must perform.
SpringDecouplingTCS_02_diprops
Characteristics:
package pl.edu.pk.ip.decoupling.springdiprops;
import java.io.FileInputStream;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
public class BusinessProcess {
public static void main(String[] args) throws Exception {
BeanFactory factory = getBeanFactory();
ServiceConsumerInterface mr = (ServiceConsumerInterface)
factory.getBean("consumer");
mr.render();
}
private static BeanFactory getBeanFactory() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader rdr = new
PropertiesBeanDefinitionReader(factory);
Properties props = new Properties();
props.load(new FileInputStream("factory.properties"));
rdr.registerBeanDefinitions(props);
return factory;
}
}
consumer.(class)=pl.edu.pk.ip.decoupling.springdiprops.ServiceConsumerImplementation
consumer.messageProvider(ref)=provider
provider.(class)=pl.edu.pk.ip.decoupling.springdiprops.ServiceProviderImplementation
Improvements:
factory.properties
factory.properties
BusinessProcess.java
9
Source code in business logic was limited to the one really necessary for executing service
consumer method. This way the whole glue code was eliminated.
Disadvantages:
The usage of low-level Spring factory is inconvenient - a lot of source code for factory
creation and for making use of java-like properties file.
Opportunities:
There are also other factories available in Spring that work on more genera level. However
they need an XML file in place of properties file.
SpringDecouplingTCS_03_dixml
Characteristics:
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-
beans.dtd">
<beans>
<bean id="consumer"
class="pl.edu.pk.ip.decoupling.springdixml.ServiceConsumerImplementation">
<property name="messageProvider">
<ref local="provider"/>
</property>
</bean>
<bean id="provider"
class="pl.edu.pk.ip.decoupling.springdixml.ServiceProviderImplementation"/>
</beans>
package pl.edu.pk.ip.decoupling.springdixml;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BusinessProcess {
public static void main(String[] args) throws Exception {
BeanFactory factory = getBeanFactory();
ServiceConsumerInterface mr = (ServiceConsumerInterface)
factory.getBean("consumer");
mr.render();
}
private static BeanFactory getBeanFactory() throws Exception {
BeanFactory factory = new ClassPathXmlApplicationContext("/beans.xml");
return factory;
}
}
Improvements:
Due to application of dependency injection supported by Spring framework the source code
is free from any glue code.
Disadvantages:
Message is still hardcoded into message provider.
beans.xml
BusinessProcess.java
10
Opportunities:
Message can be passed to message provider as a constructor argument.
SpringDecouplingTCS_04_dixmlctorarg
Characteristics:
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-
beans.dtd">
<beans>
<bean id="consumer"
class="pl.edu.pk.ip.decoupling.springdixmlctorarg.ServiceConsumerImplementation">
<property name="messageProvider">
<ref local="provider"/>
</property>
</bean>
<bean id="provider"
class="pl.edu.pk.ip.decoupling.springdixmlctorarg.ServiceProviderImplementation">
<constructor-arg>
<value>This is an XML bean ctor configurable message!</value>
</constructor-arg>
</bean>
</beans>
package pl.edu.pk.ip.decoupling.springdixmlctorarg;
public class ServiceProviderImplementation implements ServiceProviderInterface {
private String message;
public ServiceProviderImplementation(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
Improvements:
Configuration file is responsible for passing fixed data into objects of a particular class during
object construction. This way an initialization can be performed without any impact to the
source code.
Disadvantages:
Both service provider and service consumer are implemented in the same technology
(JavaSE+Spring). None of them can be switched to another technology nor can be reused
from different technology.
Opportunities:
Web Services may be applied in order to decouple technologies as well.
beans.xml
ServiceProviderImplementation.java
ml
11
SpringDecouplingTCS_05_annotation
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html
Characteristics:
Improvements:
Disadvantages:
Opportunities:
WSDecouplingTCS
Web Services can be implemented in many ways. However the most important goal of this analysis is
to show how WS can decouple technologies used in both sides: service provider and service
consumer.
WSDecouplingTCS_06_jaxwsapachecxf
Characteristics:
Improvements:
Disadvantages:
Opportunities:
WSDecouplingTCS_07_soa
Characteristics:
Improvements:
Disadvantages:
Opportunities:
WTPDecouplingTCS ?
12