Beyond J2EE 1.4
Peter TrögerHasso-Plattner-Institute
University of Potsdam
AgendaJ2EE Future
JSR Process, EE 5, EJB 3Sun AppServer 9, JBoss 5, OpenEJB
Dependency Injection & Inversion of ControlHivemind, Spring, PicoContainer, Plexus, Yan, Avalon, Tapestry
Object-relational persistenceHibernate, XMLBeans, Castor
Servlet-based frameworks - Struts
Sources: Sun JSR & GlassFish material, Martin Fowler homepage, different project sites
JSR ProcessJava Community Process (JCP) for development of specifications (since 1995)
Initiation (approved by executive committee)Early draft (for review by the public domain)Public draft (reference implementation, compatibility toolkit)Maintenance (document updates)
Java Specification Request (JSR)Proposed and final specifications for Java platformReview / approval process
Java EE 5 PlatformNext version of J2EE platformLatest versions of Java technology
Enterprise JavaBeans (EJB) 3.0 (JSR-220)JavaServer Faces (JSF) 1.2 (JSR-252)Servlet 2.5JavaServer Pages (JSP) 2.1Java API for Web Services (JAX-WS) 2.0 (JSR-224)Web Services Metadata (JSR-181)Java Architecture for XML Binding (JAXB) 2.0 (JSR-222)Java Persistence 1.0 (JSR-220)Common Annotations 1.0 (JSR-250)Streaming API for XML (StAX) 1.0 (JSR-173)
Java Enterprise System Application Platform Suite
Zur Anzeige wird der QuickTime™ Dekompressor „TIFF (LZW)“
benötigt.
Java EE 5 Major Features
Simplified web service supportMore web service standards supportSimplified EJB developmentNew persistence APIEasier web applications with JavaServer FacesMost specs available for review
Spec at Proposed Final Draft state - Q4 2005Java EE 5 SDK Beta release - Q1 2006Java EE 5 Final release - Q2 2006
Project GlassFishOpen Source Java EE 5 Application ServerSun AppServer Platform Edition 9
Open access to code and binariesIntegrates with NetBeans, Sun Java Studio Enterprise, EclipseStandard Edition
Advanced security, self-managing, self-healingClustering, multi-machine administration
Enterprise EditionSupport for high availability
Grizzly HTTP FrameworkHighly scalable HTTP pathThousands of connections with few Java threadsUses lower level Java NIO primitives
Easy-to-use, high-performance APIs for socket communication
Brings non-blocking sockets to the HTTP processing layerIntegrates with current Apache Tomcat HTTP Connector architecture (Tomcat 3,4,5) Replaces Apache Tomcat Coyote HTTP front-end and thread pool
High-performance buffers and parsing classes
Fast Infoset
Optimized Binary XML transport mechanism -fast web servicesTransparently used by web service communication stackTS-7187
GlassFish JBI IntegrationJava Business Integration (JBI) standard
JSR 208SOA-way of Enterprise Application IntegrationNormalized Message RouterOpenESB - Enterprise Service Bus product, out-of-box support for SOAP and JMS
Java EE web services (EJBs and Servlets) are automatically enabled in Normalized Message RouterJAXWS communication can be routed in-process to Normalized Message Router
EJB 3.0Coordinated in JSR 220POJO-based programming (Plain Old Java Object)
No more Home interfacesBackward compatibilityExtensive use of annotations, reduced need for deployment descriptorsSpecification of default behavior, reduces configuration overheadDependency injection with annotationsImproved EJB-QL (Update, Delete, Inner / Outer Join, SQL)Manager concept for entity bean POJOsLess checked exceptionsImproved performance
Read-only beansRelationship pre-fetching
Annotations as DescriptorsOnly RUNTIME annotations used
Available in class file, read by runtime, simplifies container developmentDeployment descriptors overwrite annotation configurationAnnotation for business interface and referencesBusiness interfaces are optionally generatedLifetime management through annotated functions (@PreDestroy, @PostConstruct)
@Stateless@Remotepublic class HelloWorldBean {
public String getHello() {return „Hello World“; }
@PreDestroy cleanUp() {// logic before destruction of the instance
}}
EJB 3 Example@Stateless public class PayrollBean
implements Payroll { @Resource DataSource empDB; public void setBenefitsDeduction
(int empId, double deduction) { ... Connection conn = empDB.getConnection();... } ... }
----------------------------------------------------@EJB ShoppingCart myCart;
Collection widgets = myCart.startToShop(“widgets”);
EE 5 Web Service Example@WebService(name=”MySimpleWS”);public class RandomClass {
@WebMethodpublic String sayHello(String s) {...} public void unpublished() {...} }
-------------------------------------------------------@WebServiceRef( wsdlLocation=
”http://localhost:8080/SayHelloService?WSDL”);)
static javaone.SayHelloService wsService;
public static void main(String[] args) { javaone.SayHello wsPort = wsService.getHello(); wsPort.sayHello(“FOSS.in Attendees”); }
AOP through Interceptorspublic class MyInterceptor {@AroundInvokepublic Object myInterceptionMethod(
InvocationContext inv) throws Exception {// Code for advicereturn inv.proceed();
}
@Interceptors({„org.example.MyInterceptor"})public class HelloWorldBean {...}
Java 6 (“Mustang”)Coordinated in JSR 270Development snapshots / sources availableNew bytecode verifier for improved performanceJFC / Swing / AWT improvement, Java 2D API, better internationalizationJava Compiler API (JSR 199)XML and Web Services (XML Signatures, JAX-WS 2.0, JAXB 2.0, JDBC 4.0, JMX 1.3)Set of improvements for Java 5 featuresSources available
Open Source Efforts beyond J2EE 1.4
Huge amount of activities to build alternatives to the J2EE 1.4 technologies
Interfaces are good abstraction, but where does the interface implementation class come from ?Heavyweight complexityComponent wiring as main problem
lightweight containers
Component Wiring –The Problempublic interface MovieFinder {
List findAll();
class MovieLister { private MovieFinder finder;
public MovieLister() {finder = new ColonDelimitedMovieFinder("movies1.txt"); }
public Movie[] moviesDirectedBy(String arg) { List allMovies = finder.findAll();for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next(); if (!movie.getDirector().equals(arg)) it.remove();
} return (Movie[]) allMovies.toArray(new
Movie[allMovies.size()]);}
}
Component Wiring Through Dependency Injection
Assembling of ‚plugin‘-style components through „Inversion of Control“ (IoC)
Separate assembler object injects an implementation into the plugin-using componentPrevents tight coupling of specific interface implementation and interface users„Dependency Injection“ pattern
Dependency Injection –Constructor Injection
Parameterized constructor of interface user takes injected implementationConfiguration code about injected objects
In different class (PicoContainer project) In XML file (NanoContainer project)
Client asks IoC framework for instancepublic void testWithPico() {
MutablePicoContainer pico = configureContainer(); MovieLister lister =
(MovieLister)pico.getComponentInstance(MovieLister.class);
Movie[] movies = lister.moviesDirectedBy("Sergio Leone"); ...}
PicoContainer Exampleclass MovieLister...
public MovieLister(MovieFinder finder) {this.finder = finder;
}
class ColonMovieFinder...public ColonMovieFinder(String filename) {
this.filename = filename;}
private MutablePicoContainer configureContainer() {MutablePicoContainer pico = new DefaultPicoContainer();Parameter[] finderParams =
{new ConstantParameter("movies1.txt")};pico.registerComponentImplementation(
MovieFinder.class, // the interfaceColonMovieFinder.class, // the implementationfinderParams);
pico.registerComponentImplementation(MovieLister.class);return pico;
}
Dependency Injection –Setter Injection
Assembler hands dependency instances through a setter method after instantiationNo atomic setting like with constructor injectionMain concept in the Spring framework
public void testWithSpring() throws Exception {
ApplicationContext ctx =
new FileSystemXmlApplicationContext("spring.xml");
MovieLister lister = (MovieLister) ctx.getBean("MovieLister");
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
}
Spring Framework Exampleclass MovieLister...
private MovieFinder finder;public void setFinder(MovieFinder finder) {
this.finder = finder;}
class ColonMovieFinder...public void setFilename(String filename) {
this.filename = filename;}
<beans><bean id="MovieLister" class="spring.MovieLister">
<property name="finder"><ref local="MovieFinder"/></property></bean><bean id="MovieFinder" class="spring.ColonMovieFinder">
<property name="filename"><value>movies1.txt</value></property></bean>
</beans>
Dependency Injection –Interface Injection
Specific interface for injection of an interface-implementing instanceInjection-interface is implemented by plugin-interface userUsed in Apache Avalon project
class IfaceTester {
public void testIface() {
configureContainer();
MovieLister lister =
(MovieLister)container.lookup("MovieLister");
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");}
}
Avalon Example
public interface InjectFinder { void injectFinder(MovieFinder finder);
} class MovieLister implements InjectFinder {
public void injectFinder(MovieFinder finder) {this.finder = finder;
}}
public interface InjectFinderFilename {void injectFilename (String filename);
}class ColonMovieFinder implements MovieFinder, InjectFinderFilename {
public void injectFilename(String filename) {this.filename = filename;
}}
Avalon Configuration Exampleclass Tester {
private Container container;private void configureContainer() {
container = new Container();registerComponents();registerInjectors();container.start(); }
private void registerComponents() {container.registerComponent("MovieLister",
MovieLister.class);container.registerComponent("MovieFinder",
ColonMovieFinder.class); }
private void registerInjectors() {container.registerInjector(InjectFinder.class,
container.lookup("MovieFinder"));container.registerInjector(InjectFinderFilename.class,
new FinderFilenameInjector());}
Component Wiring Through Service Locator
One well-known registry object knows how to get hold of all the objects the application might need
Service Locator Exampleclass MovieLister {
MovieFinder finder = ServiceLocator.movieFinder(); }
class ServiceLocator {private static ServiceLocator soleInstance; private MovieFinder movieFinder;
public static void load(ServiceLocator arg) { soleInstance = arg; }
public ServiceLocator(MovieFinder movieFinder) {this.movieFinder = movieFinder;
}
public static MovieFinder movieFinder() {return soleInstance.movieFinder;
}}
Service Locator Client Exampleclass Tester {
private void configure() {ServiceLocator.load(
new ServiceLocator(new ColonMovieFinder("movies1.txt")));
}
public void testSimple() {
configure();
MovieLister lister = new MovieLister();Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
}
}
Dynamic Service Locator Exampleclass ServiceLocator {
private static ServiceLocator soleInstance;
private Map services = new HashMap();
public static void load(ServiceLocator arg) {
soleInstance = arg; }
public static Object getService(String key){
return soleInstance.services.get(key); }
public void loadService (String key, Object service) {services.put(key, service); }
Dynamic Service Locator Client Exampleclass Tester {
private void configure() {
ServiceLocator locator = new ServiceLocator(); locator.loadService("MovieFinder",
new ColonMovieFinder("movies1.txt")); ServiceLocator.load(locator);
}
class MovieLister() {MovieFinder finder = (MovieFinder)
ServiceLocator.getService("MovieFinder");}
Service Locator vs. Dependency Injection
Decoupled application code and interface implementationService Locator
Application class asks explicitly for implementationEvery plugin depends on a specific locator –non-planned application usage might be hard
Dependency InjectionImplicit availability of interface implementationHard to debugVery easy testing (stubs / mocks for implementation)
Other discussionsConstructor vs. setter injection (related to OO principles)Code vs. configuration files
Pico Container
Small containerConfiguration support through Java objectsPreferred mode of constructor injectionNice autowiring
Spring Framework 1.2Based on J2EE practice book:Rod Johnson, Expert One-on-One J2EE Design and Development, WROX, October 2002, ISBN: 0-7645-4385-7Layered Java/J2EE application framework
Use only parts of it if you like toOpen Source project since 2003Functionality can be used in any J2EE server, most also in non-managed environmentsReusable business POJOs, based on layered Spring architecture featuresJavaBeans for application configuration (IoC)Better testability of developed codeStrict usage of interface approachAvoid checked exception concept
Spring Framework FeaturesLightweight container
Centralized, automated configuration and plumbingPOJOs as components
Common abstraction layer for transactions, not tied to J2EE (in contrast to JTA / EJB)JDBC abstraction layer with better error handlingAOP support for all objectsIntegration of other technologies (Commons Logging, Hibernate, JDO)MVC web application frameworkIndependent from underlying application serverActs as ‚glue code‘ for J2EE APIs and open source frameworks
Spring Feature Stack
Layered Spring Application
Remoting Usage Scenario
POJO Reuse ScenarioWrap existing POJOs in stateless session EJBsAccess and abstraction layer
Spring PackagesCore: bean container functionality, support for dependency injectiobContext: resembling of JNDI, supports event propagation, text messaging and wiringDAO: JDBC abstraction layerORM: Integration layers for O/R solutionsAOP: Method interceptors, pointcutsWeb / Web MVC: Web-oriented integration features
Spring Lightweight ContainerBeanFactory as container (instantiation, configuration, management)
Multiple implementations (e.g. XmlBeanFactory)Uses configuration data about dependenciesSupports different injection paradigmsSupports autowiring (by inject property name, by property type, by constructor argument type) Supports dependency checking
Resource res = new FileSystemResource("beans.xml");XmlBeanFactory factory = new XmlBeanFactory(res);
Spring DataSource Example<beans>
<bean id="myDataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/mydb" /><property name="username" value="someone" />
</bean><bean id="exampleDataAccessObject"
class="example.ExampleDataAccessObject"><property name="dataSource" ref="myDataSource" />
</bean><bean id="exampleBusinessObject"
class="example.ExampleBusinessObject"><property name="dataAccessObject">
<ref bean="exampleDataAccessObject"/></property><property name="exampleParam"><value>10</value></property>
</bean></beans>
Spring DataSource Example
<beans><bean id="myDataSource"
class="org.springframework.jndi.JndiObjectFactoryBean"><property name="jndiName" value="jdbc/myDataSource" />
</bean><bean id="exampleDataAccessObject"
class="example.ExampleDataAccessObject"><property name="dataSource" ref="myDataSource" />
</bean><bean id="exampleBusinessObject"
class="example.ExampleBusinessObject"><property name="dataAccessObject">
<ref bean="exampleDataAccessObject"/></property><property name="exampleParam"><value>10</value></property>
</bean></beans>
Spring DataSource Client
public class ExampleBusinessObject implements MyBusinessObject {
private ExampleDataAccessObject dao;
private int exampleParam;
public void setDataAccessObject(ExampleDataAccessObject dao) {
this.dao = dao;}
public void setExampleParam(int exampleParam) {
this.exampleParam = exampleParam;
}
public void myBusinessMethod() {
// do stuff using dao}}
EJB Implementation with Spring
EJBs are hard to test outside the containerSolution: Refactor business logic into POJOs behind EJB facades, including IoC patternSpring superclass implements EJB lifecylce methodsStill needed to write according ejb-jar.xml
import org.springframework.ejb.support.AbstractStatelessSessionBean;
public class MyEJB extends AbstractStatelessSessionBeanimplements MyBusinessInterface { private MyPOJO myPOJO; protected void onEjbCreate() {
this.myPOJO = getBeanFactory().getBean("myPOJO"); } public void myBusinessMethod() {
this.myPOJO.invokeMethod(); }}
Jakarta HiveMindApache Jakarta projectService and configuration framework
HiveMind services are POJOsFramework covers instantiation and configuration
Supports application development, HiveMind is not an application serverService collaboration through dependency injection microkernelConversion of user-defined configuration data into data objectsModule deployment descriptors parsed by startup logic, the ‚core‘ of HiveMindControlled instantiation and initialization of Java code
HiveMind Details
Zur Anzeige wird der QuickTime™ Dekompressor „TIFF (Unkomprimiert)“
benötigt.
Flexible, loosely-coupled configuration management and services frameworkHiveMind might be used to front EJBs, and therefore is thread-safeDependency injection for beans or larger components, called modulesEnforces interface usageStrong relation to Apache Jakarta Tapestry(Howard Lewis Ship)
HiveMind ResponsibilitiesCode
Obtain a reference to the registry SingletonKnow the ID / class type of the service to accessPass the interface class
HiveMindFind and create the according implementation objectOperate in a thread-safe mannerDo useful error reportingSupport documentation of linked extension points (HiveDoc)
HiveMind Service Referring
private SomeOtherService _otherService;public String myMethod(String param){if (_otherService == null)
_otherService = // Lookup other service . . ._otherService.doSomething(. . .);. . .
}
private SomeOtherService _otherService;public void setOtherService(SomeOtherService otherService){ _otherService = otherService; }
public String myMethod(String param){_otherService.doSomething(. . .);. . .
}
HiveMind Wiring Example (1)
package hivemind.examples;public interface Adder {
public int add(int arg0, int arg1); }
package hivemind.examples.impl;import hivemind.examples.Adder;public class AdderImpl implements Adder { public int add(int arg0, int arg1) {return arg0 + arg1;}
}
package hivemind.examples;public interface Calculator extends Adder, Subtracter{
}
HiveMind Wiring Example (2)package hivemind.examples.impl;import hivemind.examples.*;
public class CalculatorImpl implements Calculator{private Adder _adder; private Subtracter _subtracter;
public void setAdder(Adder adder){ _adder = adder; }
public void setSubtracter(Subtracter subtracter){ _subtracter = subtracter; }
public int add(int arg0, int arg1){ return _adder.add(arg0, arg1); }
public int subtract(int arg0, int arg1){ return _subtracter.subtract(arg0, arg1); }
}
HiveMind Wiring Example (3)
<?xml version="1.0"?><module id="hivemind.examples" version="1.0.0" package="hivemind.examples">
<service-point id="Adder" interface="Adder"><create-instance class="impl.AdderImpl"/><interceptor service-id="hivemind.LoggingInterceptor"/>
</service-point>
<service-point id="Subtracter" interface="Subtracter"><create-instance class="impl.SubtracterImpl"/><interceptor service-id="hivemind.LoggingInterceptor"/>
</service-point>
<service-point id="Calculator" interface="Calculator"><invoke-factory><!-- Autowires service properties based on interface! --><construct class="impl.CalculatorImpl"/>
</invoke-factory><interceptor service-id="hivemind.LoggingInterceptor"/>
</service-point></module>
HiveMind Wiring Example (4)package hivemind.examples;
import org.apache.hivemind.Registry;import org.apache.hivemind.impl.RegistryBuilder;
public class Main{public static void main(String[] args){int arg0 = Integer.parseInt(args[0]);int arg1 = Integer.parseInt(args[1]);
Registry registry = RegistryBuilder.constructDefaultRegistry();
Calculator c = (Calculator) registry.getService(Calculator.class);
System.out.println("Inputs " + arg0 + " and " + arg1);
System.out.println("Add : " + c.add(arg0, arg1));System.out.println("Subtract: " + c.subtract(arg0, arg1));
}}
HiveMind Logging Interceptorpublic String myMethod(String param) {
if (LOG.isDebugEnabled())
LOG.debug("myMethod(" + param + ")"); String result =
// . . .
if (LOG.isDebugEnabled())
LOG.debug("myMethod() returns " + result);
return result;
}
<service-point id="MyService" interface="com.myco.MyServiceInterface">
<create-instance class="com.myco.impl.MyServiceImpl"/>
<interceptor service-id="hivemind.LoggingInterceptor"/>
</service-point>
O/R Mapping Projects
Object-relational mapping allows OO-view on tables and relations from databasesCrucial for persistency implementation
HibernatePopular open source (LGPL) O/R mapping toolUsable standalone, for POJOs and for EJBsPortable SQL extension as query language (HQL)Mapping definition through XML configuration files, with own type identifiersEasier than hand-written SQL/JDBC, more powerful that EJB 2.1 entity beans, over 15 databases supportedIntegrated caching and monitoring architectureUsable from servlets or EJB session bean façadeCompatible with open source connection poolsNo backward-compatibility between versionsContributors to JSR 220 specification, implementation in JBossEJB3 containerPart of JBoss Enterprise Middleware System
Hibernate ApproachesTop-Down: Start with JavaBeansBottom-Up: Start with relational schemaMiddle-Out: Start with mapping definitionMeet-In-Middle: Start with JavaBeans and Schema
Using Hibernate Mappings in Applications
SessionFactory: Manages all mappings, configurable through filesSession: Boundary between database and applicationTransaction: JDBC, JTA or CORBA transactions, created from session
try {SessionFactory sf =
new Configuration().configure().buildSessionFactory();} catch (HibernateException e) {…}
Session sess = sf.openSession();Transaction trx = sess.beginTransaction();Band band = new Band();band.setName("deCON");
sess.save(band);trx.commit();sess.close();
Hibernate XML Mapping File<hibernate-mapping schema="allschools"><class name="net.allschools.hbn.manual.Comment“
table="COMMENT"><id name="id" column="ID" type="integer"><generator class="sequence">
<param name="sequence">allschools.comment_id_seq</param></generator>
</id><property name="commentDate" column="COMMENT_DATE"
type="date" not-null="true" /><property name="title" column="TITLE" type="string“
not-null="true"/><property name="text" column="COMMENT_TEXT" type="string"
not-null="true"/><property name="userName" column="USER_NAME" type="string"
not-null="true"/><many-to-one name="release" column="RELEASE_ID“
class="net.allschools.hbn.manual.Release"/></class>…
</hibernate-mapping>
Hibernate RelationsOne-to-one
No foreign key specificationCascade definition regarding Update and Delete
Many-to-one / many-to-manyNeeds collection class member in the JavaBean representation
<class name="net.allschools.hbn.manual.Release" table="RELEASE"><one-to-one name="cover"
class="net.allschools.hbn.manual.Image“ cascade="none"/>
<set name="comments" cascade="none" lazy="true"><key column="release_id"/><one-to-many class="net.allschools.hbn.manual.Comment"/>
</set>
<set name="bands" table="RELEASE_BANDS" cascade="none" lazy="true"><key column="RELEASE_ID"/><many-to-many class="net.allschools.hbn.manual.Band“ column="BAND_ID"/>
</set></class>
Hibernate SessionFactoryConfiguration
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD
2.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"><hibernate-configuration><session-factory name="java:comp/env/hibernate/SessionFactory"><!-- properties --><property name="hibernate.connection.driver_class">org.postgresql.Driver</property><property name="hibernate.connection.url">jdbc:postgresql:allschools</property><property name="hibernate.connection.username">username</property><property name="hibernate.connection.password">passwort</property><property name="hibernate.connection.pool_size">5</property><property name="dialect">net.sf.hibernate.dialect.PostgreSQLDialect</property><property name="show_sql">true</property><property name="use_outer_join">true</property><!-- mapping files --><mapping resource="Mappings.hbm.xml"/></session-factory></hibernate-configuration>
Hibernate Features
Hibernate Query LanguageOO-dialect of SQL – classes, properties, polymorphism, relational operations, subqueriesNative SQL with pass-through still allowed
Criteria queries (QBC)Framework for query objectsIncludes ‘query by example’
Hibernate Query LanguageList allAuctions =
session.createQuery(“from AuctionItem”).list();
select itemfrom AuctionItem itemjoin item.bids as bid
where item.description like “Hibernate%”and bid.amount > 100
XML BeansApache XMLBeans project, donated by BEABinding tool for Java object-view on XML dataMajor APIs
Strongly-typed access with XMLObject base typeXML infoset access through XMLCursor interfaceXML schema object model acces (SchemaType interface)
XML infoset is FULLY preservedXML data is still represented in memory
JAXB supports only parts of XML schemaNo marshalling / demarshalling needed
XMLBeans StepsCompile schema definitionscomp -out employeeschema.jar employeeschema.xsdWrite code
File xmlFile = new File("c:\employees.xml");
// Bind the instance to the generated XMLBeans types. EmployeesDocument empDoc =
EmployeesDocument.Factory.parse(xmlFile);
// Get and print pieces of the XML instance. Employees emps = empDoc.getEmployees(); Employee[] empArray = emps.getEmployeeArray(); for (int i = 0; i < empArray.length; i++) {
System.out.println(empArray[i]); }
XMLBeans Mapping of Schema Built-In Types
Servlet-based Technology
Apache Jakarta StrutsApplication framework for building web applications on-top-of J2EE web containerPrebuild components to be assembled to web applications -> time savingMVC design pattern as basic approach
Model components are Java classesView components are JSP files (large support for Struts custom JSP tags)Controller components are special “action classes”Struts configuration file for assembling
Several forks, confusing amount of sub-projects
Struts View Component<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %><html:html locale="true"> <head><title><bean:message key="hello.jsp.title"/></title><html:base/> </head> <body bgcolor="white"><p> <h2><bean:message key="hello.jsp.page.heading"/></h2><p><html:errors/><p> <logic:present name="examples.hello" scope="request"> <h2> Hi <bean:write name="examples.hello" property="person" />!<p> </h2>
</logic:present> <html:form action="/HelloWorld.do?action=gotName" focus="username" ><bean:message key="hello.jsp.prompt.person"/> <html:text property="person" size="16" maxlength="16"/><br> <html:submit property="submit" value="Submit"/> <html:reset/>
</html:form><br> </body> </html:html>
Struts Form Beanimport javax.servlet.http.HttpServletRequest;import org.apache.struts.action.*;
public final class HelloForm extends ActionForm {private String person = null;public String getPerson() {return (this.person);}public void setPerson(String person) {this.person = person;}
// overriden from ActionFormpublic void reset(ActionMapping mapping, HttpServletRequest request) {this.person = null;}
// overriden from ActionFormpublic ActionErrors validate(ActionMapping mapping,HttpServletRequest request) {ActionErrors errors = new ActionErrors();if ((person == null) || (person.length() < 1))
errors.add("person", new ActionError("examples.hello.no.person.error"));return errors;
}}
Struts Controller Componentpackage examples.hello;import javax.servlet.*;import org.apache.struts.action.*; …
public final class HelloAction extends Action {public ActionForward execute(ActionMapping mapping, // config file
ActionForm form, // form beanHttpServletRequest request,HttpServletResponse response) throws Exception {
ActionErrors errors = new ActionErrors();String person = (String) PropertyUtils.getSimpleProperty(form, "person");String badPerson = "Atilla the Hun";if (person.equals(badPerson)) { // business logic
errors.add("person", new ActionError("dont.talk.to.atilla", badPerson ));saveErrors(request, errors);return (new ActionForward(mapping.getInput())); }
HelloModel hm = new HelloModel(); // interact with modelhm.setPerson(person); hm.saveToPersistentStore();request.setAttribute( Constants.HELLO_KEY, hm); // pass data to view component
return (mapping.findForward("SayHello")); // forward control}}
Struts Config File<?xml version="1.0" encoding="ISO-8859-1" ?> <struts-config>
<!-- === Form Bean Definitions === --> <form-beans>
<form-bean name="HelloForm“type="examples.hello.HelloForm"/>
</form-beans> <!-- === Action Mapping Definitions === --> <action-mappings>
<!-- Say Hello! --> <action path = "/HelloWorld"
type = "examples.hello.HelloAction" name = "HelloForm" scope = "request" validate = "true" input = "/hello.jsp">
<forward name="SayHello" path="/hello.jsp" /> </action>
</action-mappings> <message-resources parameter="examples.hello.Application"/>
</struts-config>