Professional Documents
Culture Documents
1.
1.AATale
Taleof
ofTwo
TwoProjects
Projects
2.
2.Classic
ClassicJ2EE
J2EEArchitecture
Architecture
3.
3.Lightweight
Lightweight J2EE
J2EEArchitecture
Architecture
4.
4.Case
CaseStudy
Study
5.
5.Final
FinalRemarks
Remarks
A Tale of Two Projects
Minnesota
Florida
Needs same capabilities as
Started in 1990
Florida
Original cost estimate $32 million
Similar demographics
Scheduled for delivery in 1998
Started work in 1999
Development team approx 100
Finished in 2000
Revised cost estimate $170 million
Development team of 8
Revised delivery date 2005
Cost 1.1 million
Source: http://www.martinfowler.com/articles/xp2002.html
Why the difference?
Wish list
Want to be a able to build J2EE applications and
still use XP practices.
Do not want to stop doing OOP because I am
doing J2EE
Want to be able to run the code anywhere I want
Want the code to be reusable and possibly use
legacy code
Lightweight J2EE (II)
Client
State agency that needs to build several web based
applications to track budget and expenses for their
projects
Some requirements:
Each project tracks a large number of expenses
Different building types use different formulas to calculate
fees and progress
Users can modify info only before submitting for approval
Users want to delegate all or part of their responsibilities
to other users
Client’s Project Administrators want to be able to
customize the behavior of the application.
Lightweight vs. Classic J2EE
package gov.osfc.cminvoice.service.dao.hibernate;
<beans>
<bean id="cmInvoiceService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>gov.osfc.cminvoice.service.ICMInvoiceService</value>
</property>
<property name="target">
<ref local="cmInvoiceTarget"/>
</property>
<property name="interceptorNames">
<list> Note: Interceptors order is
<value>validationInterceptor</value> important! E.g. if
<value>transactionInterceptor</value> transaction is configured
<value>reportsAdvisor</value>
after reports, reports are
<value>auditAdvisor</value>
<value>emailNotificationAdvisor</value> not part of the transaction!
</list>
</property>
</bean>
</bean>
Transaction Interceptor
<beans>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/> • Can specify different Transaction Manager
</property> e.g. can switch to JTA. Change from local
</bean>
to distributed transactions without changing code!
<bean id="transactionInterceptor" • Can use Hibernate + JDBC in same transaction
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref local="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<value>
gov.osfc.cminvoice.service.ICMInvoiceService.*=PROPAGATION_REQUIRED,-java.lang.Exception
</value>
</property>
</bean> • Multiple transactional attributes are supported
</bean> • Allows to specify attribute per method
• Allows to roll back on application exceptions
Spring in the Web Tier
Loading Spring Container
in web.xml
<web-app>
<!-- Location of the XML files that defines the root application context Applied by
ContextLoaderListener.-->
<display-name>CMInvoice</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-dataSource.xml,
classpath:/config/applicationContext-cmInvoice.xml
</param-value>
</context-param>
…..
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
…
</web-app>
Spring in the Web Tier (II)
Struts BaseAction
public abstract class BaseAction extends MappingDispatchAction{
<plug-in className="net.sf.struts.saif.SAIFPlugin">
<set-property property="interceptor-config" value="/WEB-INF/interceptor-config.xml"/>
</plug-in>
</struts-config>
Authorization (III)
public class AuthorizationInterceptor implements ActionInterceptor{
public ActionForward doIntercept(InterceptorContext context, ActionInterceptorChain chain) throws Exception {
if (gov.osfc.cminvoice.web.security.AuthorizationHelper.isAuthorized(request)) {
request.setAttribute(WebConstants.REQUEST.CALLER_PERMISSIONS,
AuthorizationHelper.getCallerPermissions(request));
return chain.doIntercept(context);
} else {
AuthorizationHelper.setAuthorizationFailedMessage(request);
ActionMapping mapping = context.getActionMapping();
return mapping.findForward("error");
} Implement doIntercept and proceed
}
if authorized
}
<interceptor-config>
<interceptor name="authorizationInterceptor"
type="gov.osfc.cminvoice.web.action.interceptor.AuthorizationInterceptor"/>
<default-interceptors>
<interceptor name="authorizationInterceptor"/>
</default-interceptors> Configure to intercept all Struts action calls
</interceptor-config>
Requirements Revisited
Solution
Use a rules engine
Provide client with an interface to define any rule they
like
Provide users with an interface to configure available
rules
Tools used: Drools, Janino and a lot of creativity!
Final Remarks
http://www.agileanswers.com/XP2005.ppt
http://www.springframework.org
http://www.hibernate.org
http://struts.apache.org/
http://www.martinfowler.com/articles/xp2002.html