diff --git a/spring-framework-reference/src/cci.xml b/spring-framework-reference/src/cci.xml index 9e1e30aea07..8b5b7561c46 100644 --- a/spring-framework-reference/src/cci.xml +++ b/spring-framework-reference/src/cci.xml @@ -1,15 +1,15 @@ - +"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> JCA CCI
Introduction - J2EE provides a specification to standardize access to enterprise information systems (EIS): - the JCA (Java Connector Architecture). This specification is divided into several different parts: + J2EE provides a specification to standardize access to enterprise + information systems (EIS): the JCA (Java Connector Architecture). This + specification is divided into several different parts: @@ -18,9 +18,10 @@ can be deployed on a J2EE application server. In such a scenario, the server manages connection pooling, transaction and security (managed mode). The application server is also responsible for managing the - configuration, which is held outside the client application. A connector - can be used without an application server as well; in this case, the - application must configure it directly (non-managed mode). + configuration, which is held outside the client application. A + connector can be used without an application server as well; in this + case, the application must configure it directly (non-managed + mode). @@ -30,16 +31,16 @@ - The aim of the Spring CCI support is to provide classes to access - a CCI connector in typical Spring style, leveraging the Spring Framework's general - resource and transaction management facilities. + The aim of the Spring CCI support is to provide classes to access a + CCI connector in typical Spring style, leveraging the Spring Framework's + general resource and transaction management facilities. - The client side of connectors doesn't alway use CCI. Some - connectors expose their own APIs, only providing JCA resource adapter to - use the system contracts of a J2EE container (connection pooling, global - transactions, security). Spring does not offer special support for such - connector-specific APIs. + The client side of connectors doesn't alway use CCI. Some + connectors expose their own APIs, only providing JCA resource adapter to + use the system contracts of a J2EE container (connection pooling, global + transactions, security). Spring does not offer special support for such + connector-specific APIs.
@@ -50,78 +51,82 @@ Connector configuration The base resource to use JCA CCI is the - ConnectionFactory interface. The connector used - must provide an implementation of this interface. + ConnectionFactory interface. The + connector used must provide an implementation of this interface. To use your connector, you can deploy it on your application - server and fetch the ConnectionFactory from the - server's JNDI environment (managed mode). The connector must be + server and fetch the ConnectionFactory + from the server's JNDI environment (managed mode). The connector must be packaged as a RAR file (resource adapter archive) and contain a ra.xml file to describe its deployment - characteristics. The actual name of the resource is specified when - you deploy it. To access it within Spring, simply use Spring's - JndiObjectFactoryBean to fetch the factory - by its JNDI name. + characteristics. The actual name of the resource is specified when you + deploy it. To access it within Spring, simply use Spring's + JndiObjectFactoryBean / + <jee:jndi-lookup> fetch the factory by its JNDI + name. Another way to use a connector is to embed it in your application (non-managed mode), not using an application server to deploy and - configure it. Spring offers the possibility to configure a connector - as a bean, through a provided FactoryBean - (LocalConnectionFactoryBean). In this manner, - you only need the connector library in the classpath (no RAR file and - no ra.xml descriptor needed). The library must - be extracted from the connector's RAR file, if necessary. + configure it. Spring offers the possibility to configure a connector as + a bean, through a provided FactoryBean + (LocalConnectionFactoryBean). In this manner, you + only need the connector library in the classpath (no RAR file and no + ra.xml descriptor needed). The library must be + extracted from the connector's RAR file, if necessary. - Once you have got access to your ConnectionFactory - instance, you can inject it into your components. These components can - either be coded against the plain CCI API or leverage Spring's support - classes for CCI access (e.g. CciTemplate). + Once you have got access to your + ConnectionFactory instance, you can + inject it into your components. These components can either be coded + against the plain CCI API or leverage Spring's support classes for CCI + access (e.g. CciTemplate). - When you use a connector in - non-managed mode, you can't use global transactions because the resource - is never enlisted / delisted in the current global transaction of the - current thread. The resource is simply not aware of any global J2EE - transactions that might be running. - + When you use a connector in non-managed mode, you can't use + global transactions because the resource is never enlisted / delisted + in the current global transaction of the current thread. The resource + is simply not aware of any global J2EE transactions that might be + running. +
- <interfacename>ConnectionFactory</interfacename> configuration in Spring + <interfacename>ConnectionFactory</interfacename> configuration in + Spring In order to make connections to the EIS, you need to obtain a - ConnectionFactory from the application server if - you are in a managed mode, or directly from Spring if you are in a - non-managed mode. + ConnectionFactory from the application + server if you are in a managed mode, or directly from Spring if you are + in a non-managed mode. - In a managed mode, you access a ConnectionFactory - from JNDI; its properties will be configured in the application server. + In a managed mode, you access a + ConnectionFactory from JNDI; its + properties will be configured in the application server. - - -]]> + <jee:jndi-lookup id="eciConnectionFactory" jndi-name="eis/cicseci"/> - In non-managed mode, you must configure the ConnectionFactory - you want to use in the configuration of Spring as a JavaBean. The + In non-managed mode, you must configure the + ConnectionFactory you want to use in the + configuration of Spring as a JavaBean. The LocalConnectionFactoryBean class offers this - setup style, passing in the ManagedConnectionFactory - implementation of your connector, exposing the application-level - CCI ConnectionFactory. + setup style, passing in the + ManagedConnectionFactory implementation of your + connector, exposing the application-level CCI + ConnectionFactory. - - - - - + <bean id="eciManagedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory"> + <property name="serverName" value="TXSERIES"/> + <property name="connectionURL" value="tcp://localhost/"/> + <property name="portNumber" value="2006"/> +</bean> - - -]]> +<bean id="eciConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean"> + <property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/> +</bean> You can't directly instantiate a specific - ConnectionFactory. You need to go through - the corresponding implementation of the + ConnectionFactory. You need to go + through the corresponding implementation of the ManagedConnectionFactory interface for your connector. This interface is part of the JCA SPI specification. @@ -131,91 +136,96 @@ Configuring CCI connections JCA CCI allow the developer to configure the connections to the - EIS using the ConnectionSpec implementation of your - connector. In order to configure its properties, you need to wrap the - target connection factory with a dedicated adapter, + EIS using the ConnectionSpec + implementation of your connector. In order to configure its properties, + you need to wrap the target connection factory with a dedicated adapter, ConnectionSpecConnectionFactoryAdapter. So, the - dedicated ConnectionSpec can be configured with the - property connectionSpec (as an inner bean). + dedicated ConnectionSpec can be + configured with the property connectionSpec (as an + inner bean). This property is not mandatory because the CCI - ConnectionFactory interface defines two different - methods to obtain a CCI connection. Some of the - ConnectionSpec properties can often be configured - in the application server (in managed mode) or on the corresponding local - ManagedConnectionFactory implementation. + ConnectionFactory interface defines two + different methods to obtain a CCI connection. Some of the + ConnectionSpec properties can often be + configured in the application server (in managed mode) or on the + corresponding local ManagedConnectionFactory + implementation. - public interface ConnectionFactory implements Serializable, Referenceable { ... Connection getConnection() throws ResourceException; Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException; ... -}]]> +} - Spring provides a ConnectionSpecConnectionFactoryAdapter - that allows for specifying a ConnectionSpec instance - to use for all operations on a given factory. If the adapter's - connectionSpec property is specified, the adapter - uses the getConnection variant without argument, - else the one with the ConnectionSpec argument. + Spring provides a + ConnectionSpecConnectionFactoryAdapter that + allows for specifying a ConnectionSpec + instance to use for all operations on a given factory. If the adapter's + connectionSpec property is specified, the adapter + uses the getConnection variant without argument, else + the one with the ConnectionSpec + argument. - - - - + <bean id="managedConnectionFactory" + class="com.sun.connector.cciblackbox.CciLocalTxManagedConnectionFactory"> + <property name="connectionURL" value="jdbc:hsqldb:hsql://localhost:9001"/> + <property name="driverName" value="org.hsqldb.jdbcDriver"/> +</bean> - - - +<bean id="targetConnectionFactory" + class="org.springframework.jca.support.LocalConnectionFactoryBean"> + <property name="managedConnectionFactory" ref="managedConnectionFactory"/> +</bean> - - - - - - - - -]]> +<bean id="connectionFactory" + class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"> + <property name="targetConnectionFactory" ref="targetConnectionFactory"/> + <property name="connectionSpec"> + <bean class="com.sun.connector.cciblackbox.CciConnectionSpec"> + <property name="user" value="sa"/> + <property name="password" value=""/> + </bean> + </property> +</bean>
Using a single CCI connection - If you want to use a single CCI connection, Spring provides a further - ConnectionFactory adapter to manage this. The - SingleConnectionFactory adapter class will open a single - connection lazily and close it when this bean is destroyed at application - shutdown. This class will expose special Connection - proxies that behave accordingly, all sharing the same underlying physical - connection. + If you want to use a single CCI connection, Spring provides a + further ConnectionFactory adapter to + manage this. The SingleConnectionFactory adapter + class will open a single connection lazily and close it when this bean + is destroyed at application shutdown. This class will expose special + Connection proxies that behave + accordingly, all sharing the same underlying physical connection. - - - - - + <bean id="eciManagedConnectionFactory" + class="com.ibm.connector2.cics.ECIManagedConnectionFactory"> + <property name="serverName" value="TEST"/> + <property name="connectionURL" value="tcp://localhost/"/> + <property name="portNumber" value="2006"/> +</bean> - - - +<bean id="targetEciConnectionFactory" + class="org.springframework.jca.support.LocalConnectionFactoryBean"> + <property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/> +</bean> - - -]]> +<bean id="eciConnectionFactory" + class="org.springframework.jca.cci.connection.SingleConnectionFactory"> + <property name="targetConnectionFactory" ref="targetEciConnectionFactory"/> +</bean> - This ConnectionFactory adapter cannot directly be - configured with a ConnectionSpec. Use an - intermediary ConnectionSpecConnectionFactoryAdapter - that the SingleConnectionFactory talks to - if you require a single connection for a specific + This ConnectionFactory adapter + cannot directly be configured with a + ConnectionSpec. Use an intermediary + ConnectionSpecConnectionFactoryAdapter that the + SingleConnectionFactory talks to if you require + a single connection for a specific ConnectionSpec.
@@ -228,53 +238,55 @@ Record conversion One of the aims of the JCA CCI support is to provide convenient - facilities for manipulating CCI records. The developer can specify the - strategy to create records and extract datas from records, for use - with Spring's CciTemplate. The following interfaces will configure the - strategy to use input and output records if you don't want to work - with records directly in your application. + facilities for manipulating CCI records. The developer can specify the + strategy to create records and extract datas from records, for use with + Spring's CciTemplate. The following interfaces + will configure the strategy to use input and output records if you don't + want to work with records directly in your application. - In order to create an input Record, the - developer can use a dedicated implementation of the + In order to create an input Record, + the developer can use a dedicated implementation of the RecordCreator interface. - public interface RecordCreator { Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException; -}]]> +} As you can see, the createRecord(..) method - receives a RecordFactory instance as parameter, - which corresponds to the RecordFactory of the - ConnectionFactory used. This reference can be - used to create IndexedRecord or - MappedRecord instances. The following sample - shows how to use the RecordCreator interface - and indexed/mapped records. + receives a RecordFactory instance as + parameter, which corresponds to the + RecordFactory of the + ConnectionFactory used. This reference + can be used to create IndexedRecord or + MappedRecord instances. The following + sample shows how to use the RecordCreator + interface and indexed/mapped records. - public class MyRecordCreator implements RecordCreator { public Record createRecord(RecordFactory recordFactory) throws ResourceException { IndexedRecord input = recordFactory.createIndexedRecord("input"); input.add(new Integer(id)); return input; } -}]]> +} - An output Record can be used to receive - data back from the EIS. Hence, a specific implementation of the - RecordExtractor interface can be passed to - Spring's CciTemplate for extracting data from the output - Record. + An output Record can be used to + receive data back from the EIS. Hence, a specific implementation of the + RecordExtractor interface can be passed + to Spring's CciTemplate for extracting data from + the output Record. - public interface RecordExtractor { Object extractData(Record record) throws ResourceException, SQLException, DataAccessException; -}]]> +} - The following sample shows how to use the RecordExtractor interface. + The following sample shows how to use the + RecordExtractor interface. - public class MyRecordExtractor implements RecordExtractor { public Object extractData(Record record) throws ResourceException { CommAreaRecord commAreaRecord = (CommAreaRecord) record; @@ -283,52 +295,56 @@ String field2 = string.substring(6,1); return new OutputObject(Long.parseLong(field1), field2); } -}]]> +}
The <classname>CciTemplate</classname> - The CciTemplate is the central class of the core CCI support package - (org.springframework.jca.cci.core). It simplifies - the use of CCI since it handles the creation and release of resources. - This helps to avoid common errors like forgetting to always close the + The CciTemplate is the central class of the + core CCI support package + (org.springframework.jca.cci.core). It simplifies the + use of CCI since it handles the creation and release of resources. This + helps to avoid common errors like forgetting to always close the connection. It cares for the lifecycle of connection and interaction - objects, letting application code focus on generating input records - from application data and extracting application data from output + objects, letting application code focus on generating input records from + application data and extracting application data from output records. The JCA CCI specification defines two distinct methods to call operations on an EIS. The CCI Interaction interface provides two execute method signatures: - public interface javax.resource.cci.Interaction { ... boolean execute(InteractionSpec spec, Record input, Record output) throws ResourceException; Record execute(InteractionSpec spec, Record input) throws ResourceException; ... -}]]> +} - Depending on the template method called, CciTemplate - will know which execute method to call on the interaction. - In any case, a correctly initialized InteractionSpec - instance is mandatory. + Depending on the template method called, + CciTemplate will know which + execute method to call on the interaction. In any + case, a correctly initialized + InteractionSpec instance is + mandatory. - CciTemplate.execute(..) can be used in two ways: + CciTemplate.execute(..) can be used in two + ways: - With direct Record arguments. In this case, - you simply need to pass the CCI input record in, and the returned object - be the corresponding CCI output record. + With direct Record arguments. + In this case, you simply need to pass the CCI input record in, and + the returned object be the corresponding CCI output record. With application objects, using record mapping. In this case, - you need to provide corresponding RecordCreator - and RecordExtractor instances. - + you need to provide corresponding + RecordCreator and + RecordExtractor instances. @@ -336,7 +352,7 @@ will be used. These methods directly correspond to those on the Interaction interface. - public class CciTemplate implements CciOperations { public Record execute(InteractionSpec spec, Record inputRecord) throws DataAccessException { ... } @@ -344,15 +360,15 @@ public void execute(InteractionSpec spec, Record inputRecord, Record outputRecord) throws DataAccessException { ... } -}]]> +} With the second approach, we need to specify the record creation - and record extraction strategies as arguments. The interfaces used - are those describe in the previous section on record conversion. - The corresponding CciTemplate methods are the + and record extraction strategies as arguments. The interfaces used are + those describe in the previous section on record conversion. The + corresponding CciTemplate methods are the following: - public class CciTemplate implements CciOperations { public Record execute(InteractionSpec spec, RecordCreator inputCreator) throws DataAccessException { ... } @@ -363,48 +379,49 @@ public Object execute(InteractionSpec spec, RecordCreator creator, RecordExtractor extractor) throws DataAccessException { ... } -}]]> +} - Unless the outputRecordCreator property is - set on the template (see the following section), every method will call - the corresponding execute method of the CCI + Unless the outputRecordCreator property is set + on the template (see the following section), every method will call the + corresponding execute method of the CCI Interaction with two parameters: - InteractionSpec and input Record, - receiving an output Record as return value. - + InteractionSpec and input + Record, receiving an output + Record as return value. CciTemplate also provides methods to create - IndexRecord and MappedRecord - outside a RecordCreator implementation, through - its createIndexRecord(..) and + IndexRecord and MappedRecord + outside a RecordCreator implementation, + through its createIndexRecord(..) and createMappedRecord(..) methods. This can be used - within DAO implementations to create Record - instances to pass into corresponding - CciTemplate.execute(..) methods. + within DAO implementations to create + Record instances to pass into + corresponding CciTemplate.execute(..) methods. - public class CciTemplate implements CciOperations { public IndexedRecord createIndexedRecord(String name) throws DataAccessException { ... } public MappedRecord createMappedRecord(String name) throws DataAccessException { ... } -}]]> +}
DAO support Spring's CCI support provides a abstract class for DAOs, - supporting injection of a ConnectionFactory - or a CciTemplate instances. The name of the - class is CciDaoSupport: It provides simple + supporting injection of a + ConnectionFactory or a + CciTemplate instances. The name of the class is + CciDaoSupport: It provides simple setConnectionFactory and - setCciTemplate methods. Internally, this - class will create a CciTemplate instance - for a passed-in ConnectionFactory, exposing - it to concrete data access implementations in subclasses. + setCciTemplate methods. Internally, this class will + create a CciTemplate instance for a passed-in + ConnectionFactory, exposing it to + concrete data access implementations in subclasses. - public abstract class CciDaoSupport { public void setConnectionFactory(ConnectionFactory connectionFactory) { ... } public ConnectionFactory getConnectionFactory() { ... } @@ -412,44 +429,47 @@ public void setCciTemplate(CciTemplate cciTemplate) { ... } public CciTemplate getCciTemplate() { ... } -}]]> +}
Automatic output record generation If the connector used only supports the - Interaction.execute(..) method with input and output - records as parameters (that is, it requires the desired output record - to be passed in instead of returning an appropriate output record), - you can set the outputRecordCreator property of the - CciTemplate to automatically generate an output - record to be filled by the JCA connector when the response is received. - This record will be then returned to the caller of the template. + Interaction.execute(..) method with input and + output records as parameters (that is, it requires the desired output + record to be passed in instead of returning an appropriate output + record), you can set the outputRecordCreator property + of the CciTemplate to automatically generate an + output record to be filled by the JCA connector when the response is + received. This record will be then returned to the caller of the + template. This property simply holds an implementation of the - RecordCreator interface, used for that purpose. - The RecordCreator interface has already been - discussed in the section entitled . - The outputRecordCreator - property must be directly specified on the CciTemplate. - This could be done in the application code like so: + RecordCreator interface, used for that + purpose. The RecordCreator interface has + already been discussed in the section entitled . The + outputRecordCreator property must be directly + specified on the CciTemplate. This could be done + in the application code like so: - + cciTemplate.setOutputRecordCreator(new EciOutputRecordCreator()); - Or (recommended) in the Spring configuration, if the CciTemplate - is configured as a dedicated bean instance: + Or (recommended) in the Spring configuration, if the + CciTemplate is configured as a dedicated bean + instance: - + <bean id="eciOutputRecordCreator" class="eci.EciOutputRecordCreator"/> - - - -]]> +<bean id="cciTemplate" class="org.springframework.jca.cci.core.CciTemplate"> + <property name="connectionFactory" ref="eciConnectionFactory"/> + <property name="outputRecordCreator" ref="eciOutputRecordCreator"/> +</bean> - As the CciTemplate class is thread-safe, it will - usually be configured as a shared instance. + As the CciTemplate class is thread-safe, + it will usually be configured as a shared instance.
@@ -458,9 +478,10 @@ The following table summarizes the mechanisms of the CciTemplate class and the corresponding methods - called on the CCI Interaction interface: - Usage of <interfacename>Interaction</interfacename> execute methods + called on the CCI Interaction + interface:
+ Usage of <interfacename>Interaction</interfacename> execute + methods @@ -581,64 +602,70 @@
- Using a CCI <interfacename>Connection</interfacename> and <interfacename>Interaction</interfacename> directly + Using a CCI <interfacename>Connection</interfacename> and + <interfacename>Interaction</interfacename> directly CciTemplate also offers the possibility to work directly with CCI connections and interactions, in the same manner - as JdbcTemplate and JmsTemplate. - This is useful when you want to perform multiple operations on a CCI - connection or interaction, for example. + as JdbcTemplate and + JmsTemplate. This is useful when you want to + perform multiple operations on a CCI connection or interaction, for + example. - The interface ConnectionCallback provides a - CCI Connection as argument, in order to perform - custom operations on it, plus the CCI ConnectionFactory - which the Connection was created with. The latter - can be useful for example to get an associated RecordFactory - instance and create indexed/mapped records, for example. + The interface ConnectionCallback + provides a CCI Connection as argument, in + order to perform custom operations on it, plus the CCI + ConnectionFactory which the + Connection was created with. The latter + can be useful for example to get an associated + RecordFactory instance and create + indexed/mapped records, for example. - public interface ConnectionCallback { Object doInConnection(Connection connection, ConnectionFactory connectionFactory) throws ResourceException, SQLException, DataAccessException; -}]]> +} - The interface InteractionCallback provides - the CCI Interaction, in order to perform custom - operations on it, plus the corresponding CCI ConnectionFactory. - + The interface InteractionCallback + provides the CCI Interaction, in order to + perform custom operations on it, plus the corresponding CCI + ConnectionFactory. - public interface InteractionCallback { Object doInInteraction(Interaction interaction, ConnectionFactory connectionFactory) throws ResourceException, SQLException, DataAccessException; -}]]> +} - InteractionSpec objects - can either be shared across multiple template calls or newly created - inside every callback method. This is completely up to the DAO implementation. + InteractionSpec objects can + either be shared across multiple template calls or newly created + inside every callback method. This is completely up to the DAO + implementation.
Example for <classname>CciTemplate</classname> usage - In this section, the usage of the CciTemplate - will be shown to acces to a CICS with ECI mode, with the IBM CICS ECI - connector. + In this section, the usage of the + CciTemplate will be shown to acces to a CICS with + ECI mode, with the IBM CICS ECI connector. Firstly, some initializations on the CCI - InteractionSpec must be done to specify which CICS - program to access and how to interact with it. + InteractionSpec must be done to specify + which CICS program to access and how to interact with it. - ECIInteractionSpec interactionSpec = new ECIInteractionSpec(); interactionSpec.setFunctionName("MYPROG"); -interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);]]> +interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE); Then the program can use CCI via Spring's template and specify - mappings between custom objects and CCI Records. + mappings between custom objects and CCI + Records. - public class MyDaoImpl extends CciDaoSupport implements MyDao { public OutputObject getData(InputObject input) { ECIInteractionSpec interactionSpec = ...; @@ -661,12 +688,12 @@ interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);]]> +} - As discussed previously, callbacks can be used to work - directly on CCI connections or interactions. + As discussed previously, callbacks can be used to work directly on + CCI connections or interactions. - public class MyDaoImpl extends CciDaoSupport implements MyDao { public OutputObject getData(InputObject input) { ObjectOutput output = (ObjectOutput) getCciTemplate().execute( @@ -674,27 +701,28 @@ interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);]]>// do something...// do something... } }); } return output; } -}]]> +} - With a ConnectionCallback, - the Connection used will be managed and closed by - the CciTemplate, but any interactions created - on the connection must be managed by the callback implementation. + With a ConnectionCallback, the + Connection used will be managed and + closed by the CciTemplate, but any interactions + created on the connection must be managed by the callback + implementation. - For a more specific callback, you can implement an - InteractionCallback. The passed-in - Interaction will be managed and closed by the - CciTemplate in this case. + For a more specific callback, you can implement an + InteractionCallback. The passed-in + Interaction will be managed and closed by + the CciTemplate in this case. - public class MyDaoImpl extends CciDaoSupport implements MyDao { public String getData(String input) { ECIInteractionSpec interactionSpec = ...; @@ -712,36 +740,34 @@ interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);]]> +} For the examples above, the corresponding configuration of the involved Spring beans could look like this in non-managed mode: - - - - - - + <bean id="managedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory"> + <property name="serverName" value="TXSERIES"/> + <property name="connectionURL" value="local:"/> + <property name="userName" value="CICSUSER"/> + <property name="password" value="CICS"/> +</bean> - - - +<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean"> + <property name="managedConnectionFactory" ref="managedConnectionFactory"/> +</bean> - - -]]> +<bean id="component" class="mypackage.MyDaoImpl"> + <property name="connectionFactory" ref="connectionFactory"/> +</bean> - In managed mode (that is, in a J2EE environment), the configuration - could look as follows: + In managed mode (that is, in a J2EE environment), the + configuration could look as follows: - - - + <jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/> - - -]]> +<bean id="component" class="MyDaoImpl"> + <property name="connectionFactory" ref="connectionFactory"/> +</bean>
@@ -757,34 +783,38 @@ interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);]]>Note: This approach is internally based on the - CciTemplate class and the RecordCreator - / RecordExtractor interfaces, reusing the machinery of - Spring's core CCI support. + CciTemplate class and the + RecordCreator / + RecordExtractor interfaces, reusing the + machinery of Spring's core CCI support.
<classname>MappingRecordOperation</classname> - MappingRecordOperation essentially performs the - same work as CciTemplate, but represents a specific, - pre-configured operation as an object. It provides two template methods - to specify how to convert an input object to a input record, and how to - convert an output record to an output object (record mapping): + MappingRecordOperation essentially performs + the same work as CciTemplate, but represents a + specific, pre-configured operation as an object. It provides two + template methods to specify how to convert an input object to a input + record, and how to convert an output record to an output object (record + mapping): createInputRecord(..) to specify how to - convert an input object to an input Record + convert an input object to an input + Record extractOutputData(..) to specify how to - extract an output object from an output Record + extract an output object from an output + Record Here are the signatures of these methods: - public abstract class MappingRecordOperation extends EisOperation { ... protected abstract Record createInputRecord(RecordFactory recordFactory, Object inputObject) throws ResourceException, DataAccessException { ... } @@ -792,28 +822,29 @@ interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);]]> +} Thereafter, in order to execute an EIS operation, you need to use a single execute method, passing in an application-level input object - and receiving an application-level output object as result: + and receiving an application-level output object as result: - public abstract class MappingRecordOperation extends EisOperation { ... public Object execute(Object inputObject) throws DataAccessException { ... -}]]> +} - As you can see, contrary to the CciTemplate class, - this execute(..) method does not have an - InteractionSpec as argument. Instead, the - InteractionSpec is global to the operation. - The following constructor must be used to instantiate an operation - object with a specific InteractionSpec: + As you can see, contrary to the CciTemplate + class, this execute(..) method does not have an + InteractionSpec as argument. Instead, the + InteractionSpec is global to the + operation. The following constructor must be used to instantiate an + operation object with a specific + InteractionSpec: - InteractionSpec spec = ...; MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec); -...]]> +...
@@ -824,13 +855,13 @@ MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnecti returned by it. Spring provides a special operation class for working directly on COMMAREA rather than on records. The MappingCommAreaOperation class extends the - MappingRecordOperation class to provide such special - COMMAREA support. It implicitly uses the CommAreaRecord - class as input and output record type, and provides two new methods to - convert an input object into an input COMMAREA and the output COMMAREA - into an output object. + MappingRecordOperation class to provide such + special COMMAREA support. It implicitly uses the + CommAreaRecord class as input and output record + type, and provides two new methods to convert an input object into an + input COMMAREA and the output COMMAREA into an output object. - public abstract class MappingCommAreaOperation extends MappingRecordOperation { ... protected abstract byte[] objectToBytes(Object inObject) throws IOException, DataAccessException; @@ -838,7 +869,7 @@ MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnecti protected abstract Object bytesToObject(byte[] bytes) throws IOException, DataAccessException; ... -}]]> +}
@@ -847,77 +878,81 @@ MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnecti As every MappingRecordOperation subclass is based on CciTemplate internally, the same way to automatically generate output records as with CciTemplate is available. - Every operation object provides a corresponding - setOutputRecordCreator(..) method. For further information, - see the section entitled . + Every operation object provides a corresponding + setOutputRecordCreator(..) method. For further + information, see the section entitled .
Summary - The operation object approach uses records in the same manner - as the CciTemplate class. - + The operation object approach uses records in the same manner as + the CciTemplate class. +
- Usage of Interaction execute methods + Usage of Interaction execute methods - - - - MappingRecordOperation method - signature + + + + MappingRecordOperation + method signature - MappingRecordOperation - outputRecordCreator property + MappingRecordOperation + outputRecordCreator property - execute method called on the CCI - Interaction - - + execute method called on the CCI + Interaction + + - - - Object execute(Object) + + + Object execute(Object) - not set + not set - Record execute(InteractionSpec, - Record) - + Record execute(InteractionSpec, + Record) + - - Object execute(Object) + + Object execute(Object) - set + set - boolean execute(InteractionSpec, Record, - Record) - - - -
+ boolean execute(InteractionSpec, Record, + Record) + + + +
- Example for <classname>MappingRecordOperation</classname> usage + Example for <classname>MappingRecordOperation</classname> + usage In this section, the usage of the MappingRecordOperation will be shown to access a database with the Blackbox CCI connector. - The original version of this connector is provided by the J2EE SDK - (version 1.3), available from Sun. + The original version of this connector is provided by the J2EE + SDK (version 1.3), available from Sun. Firstly, some initializations on the CCI - InteractionSpec must be done to specify which SQL - request to execute. In this sample, we directly define the way to - convert the parameters of the request to a CCI record and the way to + InteractionSpec must be done to specify + which SQL request to execute. In this sample, we directly define the way + to convert the parameters of the request to a CCI record and the way to convert the CCI result record to an instance of the Person class. - public class PersonMappingOperation extends MappingRecordOperation { public PersonMappingOperation(ConnectionFactory connectionFactory) { setConnectionFactory(connectionFactory); @@ -946,85 +981,84 @@ MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnecti } return person; } -}]]> +} Then the application can execute the operation object, with the - person identifier as argument. Note that operation object could be - set up as shared instance, as it is thread-safe. + person identifier as argument. Note that operation object could be set + up as shared instance, as it is thread-safe. - public class MyDaoImpl extends CciDaoSupport implements MyDao { public Person getPerson(int id) { PersonMappingOperation query = new PersonMappingOperation(getConnectionFactory()); Person person = (Person) query.execute(new Integer(id)); return person; } -}]]> +} - The corresponding configuration of Spring beans could look - as follows in non-managed mode: + The corresponding configuration of Spring beans could look as + follows in non-managed mode: - - - - + <bean id="managedConnectionFactory" + class="com.sun.connector.cciblackbox.CciLocalTxManagedConnectionFactory"> + <property name="connectionURL" value="jdbc:hsqldb:hsql://localhost:9001"/> + <property name="driverName" value="org.hsqldb.jdbcDriver"/> +</bean> - - - +<bean id="targetConnectionFactory" + class="org.springframework.jca.support.LocalConnectionFactoryBean"> + <property name="managedConnectionFactory" ref="managedConnectionFactory"/> +</bean> - - - - - - - - - +<bean id="connectionFactory" + class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"> + <property name="targetConnectionFactory" ref="targetConnectionFactory"/> + <property name="connectionSpec"> + <bean class="com.sun.connector.cciblackbox.CciConnectionSpec"> + <property name="user" value="sa"/> + <property name="password" value=""/> + </bean> + </property> +</bean> - - -]]> +<bean id="component" class="MyDaoImpl"> + <property name="connectionFactory" ref="connectionFactory"/> +</bean> - In managed mode (that is, in a J2EE environment), the configuration - could look as follows: + In managed mode (that is, in a J2EE environment), the + configuration could look as follows: - - - + <jee:jndi-lookup id="targetConnectionFactory" jndi-name="eis/blackbox"/> - - - - - - - - - +<bean id="connectionFactory" + class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"> + <property name="targetConnectionFactory" ref="targetConnectionFactory"/> + <property name="connectionSpec"> + <bean class="com.sun.connector.cciblackbox.CciConnectionSpec"> + <property name="user" value="sa"/> + <property name="password" value=""/> + </bean> + </property> +</bean> - - -]]> +<bean id="component" class="MyDaoImpl"> + <property name="connectionFactory" ref="connectionFactory"/> +</bean>
- Example for <classname>MappingCommAreaOperation</classname> usage + Example for <classname>MappingCommAreaOperation</classname> + usage In this section, the usage of the MappingCommAreaOperation will be shown: accessing a CICS with ECI mode with the IBM CICS ECI connector. - Firstly, the CCI InteractionSpec needs to be - initialized to specify which CICS program to access and how to interact - with it. + Firstly, the CCI InteractionSpec + needs to be initialized to specify which CICS program to access and how + to interact with it. - public abstract class EciMappingOperation extends MappingCommAreaOperation { public EciMappingOperation(ConnectionFactory connectionFactory, String programName) { setConnectionFactory(connectionFactory); @@ -1041,13 +1075,13 @@ MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnecti return new CommAreaRecord(); } } -}]]> +} The abstract EciMappingOperation class can then be subclassed to specify mappings between custom objects and - Records. + Records. - public class MyDaoImpl extends CciDaoSupport implements MyDao { public OutputObject getData(Integer id) { EciMappingOperation query = new EciMappingOperation(getConnectionFactory(), "MYPROG") { @@ -1066,93 +1100,93 @@ MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnecti return (OutputObject) query.execute(new Integer(id)); } -}]]> +} - The corresponding configuration of Spring beans could look - as follows in non-managed mode: + The corresponding configuration of Spring beans could look as + follows in non-managed mode: - - - - - - + <bean id="managedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory"> + <property name="serverName" value="TXSERIES"/> + <property name="connectionURL" value="local:"/> + <property name="userName" value="CICSUSER"/> + <property name="password" value="CICS"/> +</bean> - - - +<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean"> + <property name="managedConnectionFactory" ref="managedConnectionFactory"/> +</bean> - - -]]> +<bean id="component" class="MyDaoImpl"> + <property name="connectionFactory" ref="connectionFactory"/> +</bean> - In managed mode (that is, in a J2EE environment), the configuration - could look as follows: + In managed mode (that is, in a J2EE environment), the + configuration could look as follows: - - - + <jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/> - - -]]> +<bean id="component" class="MyDaoImpl"> + <property name="connectionFactory" ref="connectionFactory"/> +</bean>
Transactions - JCA specifies several levels of transaction support for resource adapters. - The kind of transactions that your resource adapter supports is specified - in its ra.xml file. There are essentially three options: - none (for example with CICS EPI connector), local transactions (for - example with a CICS ECI connector), global transactions (for example with an - IMS connector). + JCA specifies several levels of transaction support for resource + adapters. The kind of transactions that your resource adapter supports is + specified in its ra.xml file. There are essentially + three options: none (for example with CICS EPI connector), local + transactions (for example with a CICS ECI connector), global transactions + (for example with an IMS connector). - + <connector> - + <resourceadapter> - ]]><!-- <transaction-support>NoTransaction</transaction-support> --><!-- <transaction-support>LocalTransaction</transaction-support> -->XATransaction + <!-- <transaction-support>NoTransaction</transaction-support> --> + <!-- <transaction-support>LocalTransaction</transaction-support> --> + <transaction-support>XATransaction</transaction-support> - + <resourceadapter> -]]> +<connector> For global transactions, you can use Spring's generic transaction - infrastructure to demarcate transactions, with JtaTransactionManager as - backend (delegating to the J2EE server's distributed transaction coordinator - underneath). + infrastructure to demarcate transactions, with + JtaTransactionManager as backend (delegating to the + J2EE server's distributed transaction coordinator underneath). - For local transactions on a single CCI ConnectionFactory, - Spring provides a specific transaction management strategy for CCI, analogous - to the DataSourceTransactionManager for JDBC. The CCI API + For local transactions on a single CCI + ConnectionFactory, Spring provides a + specific transaction management strategy for CCI, analogous to the + DataSourceTransactionManager for JDBC. The CCI API defines a local transaction object and corresponding local transaction - demarcation methods. Spring's CciLocalTransactionManager - executes such local CCI transactions, fully compliant with Spring's generic - PlatformTransactionManager abstraction. + demarcation methods. Spring's + CciLocalTransactionManager executes such local CCI + transactions, fully compliant with Spring's generic + PlatformTransactionManager + abstraction. - - - + <jee:jndi-lookup id="eciConnectionFactory" jndi-name="eis/cicseci"/> - - -]]> +<bean id="eciTransactionManager" + class="org.springframework.jca.cci.connection.CciLocalTransactionManager"> + <property name="connectionFactory" ref="eciConnectionFactory"/> +</bean> - Both transaction strategies can be used with any of Spring's - transaction demarcation facilities, be it declarative or programmatic. - This is a consequence of Spring's generic - PlatformTransactionManager abstraction, which - decouples transaction demarcation from the actual execution strategy. - Simply switch between JtaTransactionManager and - CciLocalTransactionManager as needed, keeping - your transaction demarcation as-is. + Both transaction strategies can be used with any of Spring's + transaction demarcation facilities, be it declarative or programmatic. + This is a consequence of Spring's generic + PlatformTransactionManager abstraction, + which decouples transaction demarcation from the actual execution + strategy. Simply switch between + JtaTransactionManager and + CciLocalTransactionManager as needed, keeping your + transaction demarcation as-is. - For more information on Spring's transaction facilities, see the - chapter entitled . + For more information on Spring's transaction facilities, see the + chapter entitled .
diff --git a/spring-framework-reference/src/jms.xml b/spring-framework-reference/src/jms.xml index ae5c55d08b7..2e1746797c1 100644 --- a/spring-framework-reference/src/jms.xml +++ b/spring-framework-reference/src/jms.xml @@ -198,7 +198,8 @@ Destinations, like ConnectionFactories, are JMS administered objects that can be stored and retrieved in JNDI. When configuring a Spring application context you can use the JNDI factory class - JndiObjectFactoryBean to perform dependency + JndiObjectFactoryBean / + <jee:jndi-lookup> to perform dependency injection on your object's references to JMS destinations. However, often this strategy is cumbersome if there are a large number of destinations in the application or if there are advanced destination diff --git a/spring-framework-reference/src/orm.xml b/spring-framework-reference/src/orm.xml index 9ce6e2d7b65..82793bb8c3b 100644 --- a/spring-framework-reference/src/orm.xml +++ b/spring-framework-reference/src/orm.xml @@ -286,15 +286,14 @@ public class ProductDaoImpl implements ProductDao { <beans> - <bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> - <property name="jndiName" value="java:comp/env/jdbc/myds"/> - </bean> + <jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/> </beans> You can also access a JNDI-located SessionFactory, using Spring's - JndiObjectFactoryBean to retrieve and expose it. + JndiObjectFactoryBean / + <jee:jndi-lookup> to retrieve and expose it. However, that is typically not common outside of an EJB context. @@ -618,13 +617,9 @@ public class ProductDaoImpl implements ProductDao { <beans> - <bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean"> - <property name="jndiName value="java:comp/env/jdbc/myds1"/> - </bean> + <jee:jndi-lookup id="dataSource1" jndi-name="java:comp/env/jdbc/myds1"/> - <bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean"> - <property name="jndiName" value="java:comp/env/jdbc/myds2"/> - </bean> + <jee:jndi-lookup id="dataSource2" jndi-name="java:comp/env/jdbc/myds2"/> <bean id="mySessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource1"/> @@ -795,7 +790,8 @@ public class ProductDaoImpl implements ProductDao { If in your application context you are already directly obtaining the JTA PlatformTransactionManager object - (presumably from JNDI via JndiObjectFactoryBean) + (presumably from JNDI via + JndiObjectFactoryBean/<jee:jndi-lookup>) and feeding it for example to Spring's JtaTransactionManager, then the easiest way is to simply specify a reference to this as the value of @@ -953,12 +949,13 @@ public class ProductDaoImpl implements ProductDao { A JDO PersistenceManagerFactory can also be set up in the JNDI environment of a J2EE application server, usually through the JCA connector provided by the particular JDO - implementation. Spring's standard - JndiObjectFactoryBean can be used to retrieve and - expose such a PersistenceManagerFactory. - However, outside an EJB context, there is often no compelling benefit in - holding the PersistenceManagerFactory in - JNDI: only choose such setup for a good reason. See "container resources + implementation. Spring's standard JndiObjectFactoryBean / + <jee:jndi-lookup> can be used to + retrieve and expose such a + PersistenceManagerFactory. However, + outside an EJB context, there is often no compelling benefit in holding + the PersistenceManagerFactory in JNDI: + only choose such setup for a good reason. See "container resources versus local resources" in the Hibernate section for a discussion; the arguments there apply to JDO as well. diff --git a/spring-framework-reference/src/testing.xml b/spring-framework-reference/src/testing.xml index 25c56976099..b88e6faac07 100644 --- a/spring-framework-reference/src/testing.xml +++ b/spring-framework-reference/src/testing.xml @@ -1,7 +1,6 @@ - +"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> Testing @@ -22,8 +21,8 @@ One of the main benefits of Dependency Injection is that your code should really depend far less on the container than in traditional J2EE - development. The POJOs that make up your application should be testable - in JUnit or TestNG tests, with objects simply instantiated using the + development. The POJOs that make up your application should be testable in + JUnit or TestNG tests, with objects simply instantiated using the new operator, without Spring or any other container. You can use mock objects (in conjunction with many other valuable testing @@ -120,21 +119,20 @@ Spring MVC The org.springframework.test.web package - contains ModelAndViewAssert, which can be - used in combination with any testing framework (e.g., JUnit 4+, - TestNG, etc.) for unit tests dealing with Spring MVC + contains ModelAndViewAssert, which can be used + in combination with any testing framework (e.g., JUnit 4+, TestNG, + etc.) for unit tests dealing with Spring MVC ModelAndView objects. - + - Unit testing Spring MVC Controllers - - To test your Spring MVC Controllers, - use ModelAndViewAssert combined with - MockHttpServletRequest, - MockHttpSession, etc. from the org.springframework.mock.web - package. - + Unit testing Spring MVC Controllers + + To test your Spring MVC Controllers, use + ModelAndViewAssert combined with + MockHttpServletRequest, + MockHttpSession, etc. from the org.springframework.mock.web + package. @@ -165,44 +163,43 @@ The Spring Framework provides first class support for integration - testing in the org.springframework.test-VERSION.jar - library (where VERSION is the release version). In this library, - you will find the org.springframework.test package - which contains valuable classes for integration testing using a Spring - container, while at the same time not being reliant on an application - server or other deployment environment. Such tests will be slower to run - than unit tests but much faster to run than the equivalent Cactus tests - or remote tests relying on deployment to an application server. + testing in the org.springframework.test-VERSION.jar + library (where VERSION is the release version). In + this library, you will find the + org.springframework.test package which contains + valuable classes for integration testing using a Spring container, while + at the same time not being reliant on an application server or other + deployment environment. Such tests will be slower to run than unit tests + but much faster to run than the equivalent Cactus tests or remote tests + relying on deployment to an application server. + + Since Spring 2.5, unit and integration testing support is provided + in the form of the annotation-driven Spring TestContext Framework. The + TestContext Framework is agnostic of the actual testing framework in + use, thus allowing instrumentation of tests in various environments + including JUnit 3.8, JUnit 4.5, TestNG, etc. - - Since Spring 2.5, unit and integration testing support is provided - in the form of the annotation-driven Spring TestContext Framework. - The TestContext Framework is agnostic of the actual testing framework - in use, thus allowing - instrumentation of tests in various environments including JUnit 3.8, - JUnit 4.5, TestNG, etc. - - - Legacy JUnit 3.8 class hierarchy is deprecated - - As of Spring 3.0, the legacy JUnit 3.8 base class hierarchy (e.g., - AbstractDependencyInjectionSpringContextTests, - AbstractTransactionalDataSourceSpringContextTests, - etc.) is officially deprecated and will be removed in a later release. - Thus any code which depends on the legacy JUnit 3.8 support should be - migrated to the Spring TestContext Framework. - + Legacy JUnit 3.8 class hierarchy is deprecated + + As of Spring 3.0, the legacy JUnit 3.8 base class hierarchy + (e.g., + AbstractDependencyInjectionSpringContextTests, + AbstractTransactionalDataSourceSpringContextTests, + etc.) is officially deprecated and will be removed in a later release. + Thus any code which depends on the legacy JUnit 3.8 support should be + migrated to the Spring + TestContext Framework.
Goals - The following bullet points highlight the fundamental goals of Spring's - integration testing support: + The following bullet points highlight the fundamental goals of + Spring's integration testing support: @@ -227,32 +224,31 @@ - In the next few sections each of the above goals is discussed - in greater detail, and at the end of each section you will find a direct + In the next few sections each of the above goals is discussed in + greater detail, and at the end of each section you will find a direct link to implementation and configuration details pertaining to that particular goal.
Context management and caching - The Spring TestContext Framework provides consistent - loading of Spring ApplicationContexts and - caching of those contexts. Support for the caching of loaded contexts - is important, because if you are working on a large project, startup - time may become an issue - not because of the overhead of Spring - itself, but because the objects instantiated by the Spring container - will themselves take time to instantiate. For example, a project with - 50-100 Hibernate mapping files might take 10-20 seconds to load the - mapping files, and incurring that cost before running every single - test in every single test fixture will lead to slower overall test - runs that could reduce productivity. + The Spring TestContext Framework provides consistent loading of + Spring ApplicationContexts and caching of those + contexts. Support for the caching of loaded contexts is important, + because if you are working on a large project, startup time may become + an issue - not because of the overhead of Spring itself, but because + the objects instantiated by the Spring container will themselves take + time to instantiate. For example, a project with 50-100 Hibernate + mapping files might take 10-20 seconds to load the mapping files, and + incurring that cost before running every single test in every single + test fixture will lead to slower overall test runs that could reduce + productivity. - Test classes provide an array containing the - resource locations of XML configuration metadata - typically on the - classpath - used to configure the application. This will be the same, - or nearly the same, as the list of configuration locations specified - in web.xml or other deployment - configuration. + Test classes provide an array containing the resource locations + of XML configuration metadata - typically on the classpath - used to + configure the application. This will be the same, or nearly the same, + as the list of configuration locations specified in + web.xml or other deployment configuration. By default, once loaded, the configured ApplicationContext will be reused for @@ -264,22 +260,21 @@ a mechanism to cause the test fixture to reload the configurations and rebuild the application context before executing the next test. - - See: context management and caching with the - TestContext Framework. - + See: context management and caching with the TestContext + Framework.
Dependency Injection of test fixtures - When the TestContext framework loads your - application context, it can optionally configure instances of your - test classes via Dependency Injection. This provides a convenient - mechanism for setting up test fixtures using pre-configured beans from - your application context. A strong benefit here is that you can reuse - application contexts across various testing scenarios (e.g., for - configuring Spring-managed object graphs, transactional proxies, + When the TestContext framework loads your application context, + it can optionally configure instances of your test classes via + Dependency Injection. This provides a convenient mechanism for setting + up test fixtures using pre-configured beans from your application + context. A strong benefit here is that you can reuse application + contexts across various testing scenarios (e.g., for configuring + Spring-managed object graphs, transactional proxies, DataSources, etc.), thus avoiding the need to duplicate complex test fixture set up for individual test cases. @@ -311,10 +306,8 @@ - - See: dependency injection of test fixtures with the - TestContext Framework. - + See: dependency injection of test fixtures with the TestContext Framework.
@@ -323,47 +316,42 @@ One common issue in tests that access a real database is their affect on the state of the persistence store. Even when you're using a development database, changes to the state may affect future tests. - Also, many operations - such as inserting or modifying persistent - data - cannot be performed (or verified) outside a transaction. + Also, many operations - such as inserting or modifying persistent data + - cannot be performed (or verified) outside a transaction. - The TestContext framework addresses this issue. By default, - the framework will create and roll back a transaction for each - test. You simply write code that can assume the existence of a - transaction. If you call transactionally proxied objects in your - tests, they will behave correctly, according to their transactional - semantics. In addition, if test methods delete the contents of - selected tables while running within a transaction, the transaction - will roll back by default, and the database will return to its state - prior to execution of the test. Transactional support is provided to - your test class via a - PlatformTransactionManager bean defined in the - test's application context. + The TestContext framework addresses this issue. By default, the + framework will create and roll back a transaction for each test. You + simply write code that can assume the existence of a transaction. If + you call transactionally proxied objects in your tests, they will + behave correctly, according to their transactional semantics. In + addition, if test methods delete the contents of selected tables while + running within a transaction, the transaction will roll back by + default, and the database will return to its state prior to execution + of the test. Transactional support is provided to your test class via + a PlatformTransactionManager bean defined in + the test's application context. If you want a transaction to commit - unusual, but occasionally useful when you want a particular test to populate or modify the - database - the TestContext framework can be - instructed to cause the transaction to commit instead of roll back - via the - @TransactionConfiguration - and - @Rollback + database - the TestContext framework can be instructed to cause the + transaction to commit instead of roll back via the @TransactionConfiguration + and @Rollback annotations. - - See: transaction management with the - TestContext Framework. - + See: transaction management with the TestContext Framework.
Integration testing support classes - The Spring TestContext Framework provides - several abstract support classes that can simplify - writing integration tests. These base test classes provide well - defined hooks into the testing framework as well as convenient - instance variables and methods, allowing access to such things - as: + The Spring TestContext Framework provides several + abstract support classes that can simplify writing + integration tests. These base test classes provide well defined hooks + into the testing framework as well as convenient instance variables + and methods, allowing access to such things as: @@ -373,10 +361,10 @@ - A SimpleJdbcTemplate: useful for querying to - confirm state. For example, you might query before and after - testing application code that creates an object and persists it - using an ORM tool, to verify that the data appears in the + A SimpleJdbcTemplate: useful for + querying to confirm state. For example, you might query before and + after testing application code that creates an object and persists + it using an ORM tool, to verify that the data appears in the database. (Spring will ensure that the query runs in the scope of the same transaction.) You will need to tell your ORM tool to 'flush' its changes for this to work correctly, for example using @@ -385,16 +373,14 @@ - - In addition, you may find it desirable to provide your own custom, - application-wide superclass for integration tests that provides - further useful instance variables and - methods specific to your project. + In addition, you may find it desirable to provide your own + custom, application-wide superclass for integration tests that + provides further useful instance variables and methods specific to + your project. - - See: support classes for the - TestContext Framework. - + See: support classes for the TestContext + Framework.
@@ -420,37 +406,36 @@ The Spring Framework provides the following set of - Spring-specific annotations that you - can use in your unit and integration tests in conjunction with the - TestContext framework. Refer to the respective JavaDoc for - further information, including default attribute values, etc. + Spring-specific annotations that you can use in + your unit and integration tests in conjunction with the TestContext + framework. Refer to the respective JavaDoc for further information, + including default attribute values, etc.
+ + @ContextConfiguration - - @ContextConfiguration + Defines class-level metadata which is used to determine how to + load and configure an + ApplicationContext. Specifically, + @ContextConfiguration defines the application context resource + locations to load as well as the + ContextLoader strategy to use for + loading the context. - Defines class-level metadata which is used to determine how - to load and configure an - ApplicationContext. Specifically, - @ContextConfiguration defines the application context resource - locations to load as well as the - ContextLoader strategy to use for - loading the context. - - @ContextConfiguration(locations={"example/test-context.xml"}, loader=CustomContextLoader.class) + @ContextConfiguration(locations={"example/test-context.xml"}, loader=CustomContextLoader.class) public class CustomConfiguredApplicationContextTests { // class body... } - Note: @ContextConfiguration - provides support for inherited resource - locations by default. See the Context management and - caching section and JavaDoc for an example and further - details. - + Note: @ContextConfiguration + provides support for inherited resource + locations by default. See the Context management and + caching section and JavaDoc for an example and further + details. + // some logic that results in the Spring container being dirtied }
- - @TestExecutionListeners - Defines class-level metadata for configuring which - TestExecutionListeners should be - registered with a TestContextManager. - Typically, @TestExecutionListeners - will be used in conjunction with - @ContextConfiguration. + + @TestExecutionListeners - @ContextConfiguration + Defines class-level metadata for configuring which + TestExecutionListeners should be + registered with a TestContextManager. + Typically, @TestExecutionListeners + will be used in conjunction with + @ContextConfiguration. + + @ContextConfiguration @TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class}) public class CustomTestExecutionListenerTests { // class body... } - Note: @TestExecutionListeners - provides support for inherited listeners by - default. See the JavaDoc for an example and further - details. - + Note: @TestExecutionListeners + provides support for inherited listeners by + default. See the JavaDoc for an example and further details. + - - @TransactionConfiguration + + @TransactionConfiguration - Defines class-level metadata for configuring transactional - tests. Specifically, the bean name of the - PlatformTransactionManager that is - to be used to drive transactions can be explicitly configured if - the bean name of the desired PlatformTransactionManager is not - "transactionManager". In addition, the - defaultRollback flag can optionally be changed - to false. Typically, - @TransactionConfiguration will be - used in conjunction with - @ContextConfiguration. + Defines class-level metadata for configuring transactional + tests. Specifically, the bean name of the + PlatformTransactionManager that is to + be used to drive transactions can be explicitly configured if the + bean name of the desired PlatformTransactionManager is not + "transactionManager". In addition, the + defaultRollback flag can optionally be changed to + false. Typically, + @TransactionConfiguration will be + used in conjunction with + @ContextConfiguration. - @ContextConfiguration + @ContextConfiguration @TransactionConfiguration(transactionManager="txMgr", defaultRollback=false) public class CustomConfiguredTransactionalTests { // class body... } - + - - @BeforeTransaction + + @BeforeTransaction - Indicates that the annotated public void - method should be executed before a - transaction is started for test methods configured to run within a - transaction via the @Transactional - annotation. + Indicates that the annotated public void + method should be executed before a transaction + is started for test methods configured to run within a transaction + via the @Transactional + annotation. - @BeforeTransaction + @BeforeTransaction public void beforeTransaction() { // logic to be executed before a transaction is started } - + - - @AfterTransaction + + @AfterTransaction - Indicates that the annotated public void - method should be executed after a transaction - has been ended for test methods configured to run within a - transaction via the @Transactional - annotation. + Indicates that the annotated public void + method should be executed after a transaction + has been ended for test methods configured to run within a + transaction via the @Transactional + annotation. - @AfterTransaction + @AfterTransaction public void afterTransaction() { // logic to be executed after a transaction has ended } - + // ... } + - + - + The following annotations are only supported + when used in conjunction with JUnit (i.e., with the SpringJUnit4ClassRunner or + the JUnit 3.8 + and JUnit 4.5 + support classes. - The following annotations are only - supported when used in conjunction with JUnit (i.e., with the SpringJUnit4ClassRunner or - the JUnit - 3.8 and JUnit 4.5 support - classes. + + + @IfProfileValue - - - @IfProfileValue - - Indicates that the annotated test is enabled for a specific - testing environment. If the configured - ProfileValueSource returns a matching - value for the provided name, - the test will be enabled. This annotation can be applied to an - entire class or individual methods. - - @IfProfileValue(name="java.vendor", value="Sun Microsystems Inc.") + Indicates that the annotated test is enabled for a specific + testing environment. If the configured + ProfileValueSource returns a matching + value for the provided name, + the test will be enabled. This annotation can be applied to an + entire class or individual methods. + + @IfProfileValue(name="java.vendor", value="Sun Microsystems Inc.") @Test public void testProcessWhichRunsOnlyOnSunJvm() { // some logic that should run only on Java VMs from Sun Microsystems } - - Alternatively @IfProfileValue - may be configured with a list of values (with - OR semantics) to achieve TestNG-like support - for test groups in a JUnit environment. - Consider the following example: - - @IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"}) + + Alternatively @IfProfileValue + may be configured with a list of values (with + OR semantics) to achieve TestNG-like support + for test groups in a JUnit environment. + Consider the following example: + + @IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"}) @Test public void testProcessWhichRunsForUnitOrIntegrationTestGroups() { // some logic that should run only for unit and integration test groups } - + - - @ProfileValueSourceConfiguration - - Class-level annotation which is used to specify what type of - ProfileValueSource to use when retrieving - profile values configured via the - @IfProfileValue annotation. If - @ProfileValueSourceConfiguration is - not declared for a test, - SystemProfileValueSource will be used by - default. - - @ProfileValueSourceConfiguration(CustomProfileValueSource.class) + + @ProfileValueSourceConfiguration + + Class-level annotation which is used to specify what type of + ProfileValueSource to use when retrieving + profile values configured via the + @IfProfileValue annotation. If + @ProfileValueSourceConfiguration is + not declared for a test, + SystemProfileValueSource will be used by + default. + + @ProfileValueSourceConfiguration(CustomProfileValueSource.class) public class CustomProfileValueSourceTests { // class body... } - + - - @ExpectedException - - Indicates that the annotated test method is expected to throw - an exception during execution. The type of the expected exception is - provided in the annotation, and if an instance of the exception is - thrown during the test method execution then the test passes. - Likewise if an instance of the exception is not - thrown during the test method execution then the test fails. - - @ExpectedException(SomeBusinessException.class) + + @ExpectedException + + Indicates that the annotated test method is expected to throw + an exception during execution. The type of the expected exception is + provided in the annotation, and if an instance of the exception is + thrown during the test method execution then the test passes. + Likewise if an instance of the exception is not + thrown during the test method execution then the test fails. + + @ExpectedException(SomeBusinessException.class) public void testProcessRainyDayScenario() { // some logic that should result in an Exception being thrown } - Using Spring's - @ExpectedException annotation in - conjunction with JUnit 4's - @Test(expected=...) configuration - would lead to an unresolvable conflict. Developers must therefore - choose one or the other when integrating with JUnit 4, in which - case it is generally preferable to use the explicit JUnit 4 - configuration. - + Using Spring's + @ExpectedException annotation in + conjunction with JUnit 4's + @Test(expected=...) configuration + would lead to an unresolvable conflict. Developers must therefore + choose one or the other when integrating with JUnit 4, in which case + it is generally preferable to use the explicit JUnit 4 + configuration. + - - @Timed - - Indicates that the annotated test method has to finish - execution in a specified time period (in milliseconds). If the text - execution time takes longer than the specified time period, the test - fails. - - Note that the time period includes execution of the test - method itself, any repetitions of the test (see - @Repeat), as well as any - set up or tear down of the - test fixture. - - @Timed(millis=1000) + + @Timed + + Indicates that the annotated test method has to finish + execution in a specified time period (in milliseconds). If the text + execution time takes longer than the specified time period, the test + fails. + + Note that the time period includes execution of the test + method itself, any repetitions of the test (see + @Repeat), as well as any + set up or tear down of the + test fixture. + + @Timed(millis=1000) public void testProcessWithOneSecondTimeout() { // some logic that should not take longer than 1 second to execute } - Spring's @Timed annotation - has different semantics than JUnit 4's - @Test(timeout=...) support. - Specifically, due to the manner in which JUnit 4 handles test - execution timeouts (i.e., by executing the test method in a - separate Thread), - @Test(timeout=...) applies to - each iteration in the case of repetitions - and preemptively fails the test if the test takes too long. - Spring's @Timed, on the other hand, - times the total test execution time - (including all repetitions) and does not preemptively fail the test - but rather waits for the test to actually complete before failing. - + Spring's @Timed annotation has + different semantics than JUnit 4's + @Test(timeout=...) support. + Specifically, due to the manner in which JUnit 4 handles test + execution timeouts (i.e., by executing the test method in a separate + Thread), + @Test(timeout=...) applies to + each iteration in the case of repetitions and + preemptively fails the test if the test takes too long. Spring's + @Timed, on the other hand, times the + total test execution time (including all + repetitions) and does not preemptively fail the test but rather + waits for the test to actually complete before failing. + - - @Repeat - - Indicates that the annotated test method must be executed - repeatedly. The number of times that the test method is to be - executed is specified in the annotation. - - Note that the scope of execution to be repeated includes - execution of the test method itself as well as any set - up or tear down of the test - fixture. + + @Repeat - @Repeat(10) + Indicates that the annotated test method must be executed + repeatedly. The number of times that the test method is to be + executed is specified in the annotation. + + Note that the scope of execution to be repeated includes + execution of the test method itself as well as any set + up or tear down of the test + fixture. + + @Repeat(10) @Test public void testProcessRepeatedly() { // ... } - + + - + - + The following non-test-specific annotations are supported with + standard semantics for all configurations of the Spring TestContext + Framework. - - The following non-test-specific annotations are supported with - standard semantics for all - configurations of the Spring TestContext Framework. - + + + @Autowired + - - - @Autowired - + + @Qualifier + - - @Qualifier - + + @Resource + (javax.annotation) if JSR-250 is present + - - @Resource (javax.annotation) - if JSR-250 is present - + + @PersistenceContext + (javax.persistence) if JPA is present + - - @PersistenceContext - (javax.persistence) if JPA is present - + + @PersistenceUnit + (javax.persistence) if JPA is present + - - @PersistenceUnit - (javax.persistence) if JPA is present - + + @Required + - - @Required - - - - @Transactional - - + + @Transactional + +
@@ -894,15 +874,15 @@ public void testProcessRepeatedly() { therefore provide this functionality out-of-the-box. - @Autowired ApplicationContext - - As an alternative to implementing the - ApplicationContextAware interface, - your test class can have its application context injected via the - @Autowired annotation on either a - field or setter method, for example: - - @RunWith(SpringJUnit4ClassRunner.class) + @Autowired ApplicationContext + + As an alternative to implementing the + ApplicationContextAware interface, + your test class can have its application context injected via the + @Autowired annotation on either a + field or setter method, for example: + + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class MyTest { @Autowired @@ -912,20 +892,20 @@ public class MyTest { } - In contrast to the now deprecated JUnit 3.8 legacy class hierarchy, - test classes which use the TestContext framework do not need to override - any protected instance methods to configure their - application context. Rather, configuration is achieved merely by - declaring the @ContextConfiguration - annotation at the class level. If your test class does not explicitly - declare any application context resource locations, - the configured ContextLoader will - determine how and whether or not to load a context from a default set - of locations. For example, - GenericXmlContextLoader - which is the default - ContextLoader - will generate a default - location based on the name of the test class. If your class is named - com.example.MyTest, + In contrast to the now deprecated JUnit 3.8 legacy class + hierarchy, test classes which use the TestContext framework do not + need to override any protected instance methods to + configure their application context. Rather, configuration is achieved + merely by declaring the + @ContextConfiguration annotation at the + class level. If your test class does not explicitly declare any + application context resource locations, the + configured ContextLoader will determine + how and whether or not to load a context from a default set of + locations. For example, GenericXmlContextLoader + - which is the default ContextLoader - + will generate a default location based on the name of the test class. + If your class is named com.example.MyTest, GenericXmlContextLoader will load your application context from "classpath:/com/example/MyTest-context.xml". @@ -960,16 +940,16 @@ public class MyTest { // class body... } - @ContextConfiguration supports - an alias for the locations attribute via the - standard value attribute. Thus, if you do not need - to configure a custom ContextLoader, you + @ContextConfiguration supports an + alias for the locations attribute via the standard + value attribute. Thus, if you do not need to + configure a custom ContextLoader, you can omit the declaration of the locations attribute - name and declare the resource locations using the shorthand format + name and declare the resource locations using the shorthand format demonstrated in the following example. - @ContextConfiguration also - supports a boolean inheritLocations attribute which - denotes whether or not resource locations from superclasses should be + @ContextConfiguration also supports a + boolean inheritLocations attribute which denotes + whether or not resource locations from superclasses should be inherited. The default value is true, which means that an annotated class will inherit the resource locations defined by an @@ -1037,8 +1017,8 @@ public class ExtendedTest extends BaseTest { consistency with the annotation support introduced in Spring 2.5, you may choose either Spring's @Autowired annotation or the @Resource annotation - from JSR 250. The semantics for both are consistent throughout the Spring - Framework. For example, if you prefer autowiring by type, annotate your setter methods or fields with @Autowired. On the other hand, if you @@ -1063,9 +1043,8 @@ public class ExtendedTest extends BaseTest { ApplicationContext, you can perform an explicit lookup using (for example) a call to applicationContext.getBean("titleDao"). A - third option is to use @Autowired - in conjunction with @Qualifier. - + third option is to use @Autowired in + conjunction with @Qualifier. If you don't want dependency injection applied to your test instances, simply don't annotate any fields or setter methods with @@ -1079,14 +1058,14 @@ public class ExtendedTest extends BaseTest { Consider the scenario where we have a class, HibernateTitleDao (as outlined in the Goals section). First, - let's look at a JUnit 4.5 based implementation of the test class - itself which uses @Autowired for field - injection (we will look at the application context configuration after - all sample code listings). Note: The dependency injection - behavior in the following code listings is not in any way specific to - JUnit 4.5. The same DI techniques can be used in conjunction with any - testing framework. + linkend="testing-fixture-di">Goals section). First, let's look + at a JUnit 4.5 based implementation of the test class itself which + uses @Autowired for field injection (we + will look at the application context configuration after all sample + code listings). Note: The dependency injection behavior in + the following code listings is not in any way specific to JUnit 4.5. + The same DI techniques can be used in conjunction with any testing + framework. @RunWith(SpringJUnit4ClassRunner.class) // specifies the Spring configuration to load for this test fixture @@ -1200,12 +1179,14 @@ public final class HibernateTitleDaoTests { </beans> - If you are extending from a Spring-provided test base class that happens - to use @Autowired on one of its setters methods, - you might have multiple beans of the affected type defined in your application context: - e.g. multiple DataSource beans. In such a case, - you may override the setter and use the @Qualifier - annotation to indicate a specific target bean as follows: + If you are extending from a Spring-provided test base class + that happens to use @Autowired on one + of its setters methods, you might have multiple beans of the + affected type defined in your application context: e.g. multiple + DataSource beans. In such a case, you + may override the setter and use the + @Qualifier annotation to indicate a + specific target bean as follows: ... @Override @Autowired @@ -1215,22 +1196,23 @@ public final class HibernateTitleDaoTests { ... The specified qualifier value indicates the specific - DataSource bean to inject, - narrowing the set of type matches to a specific bean. - Its value is matched against <qualifier> - declarations within the corresponding <bean> - definitions. The bean name is used as a fallback qualifier value, - so you may effectively also point to a specific bean by name there - (as shown above, assuming that "myDataSource" is the bean id). - If there is only one DataSource bean - to begin with, then the qualifier will simply not have any effect - - independent from the bean name of that single matching bean. + DataSource bean to inject, narrowing + the set of type matches to a specific bean. Its value is matched + against <qualifier> declarations within the + corresponding <bean> definitions. The bean + name is used as a fallback qualifier value, so you may effectively + also point to a specific bean by name there (as shown above, + assuming that "myDataSource" is the bean id). If there is only one + DataSource bean to begin with, then + the qualifier will simply not have any effect - independent from the + bean name of that single matching bean. - Alternatively, consider using the @Resource - annotation on such an overridden setter methods, defining the - target bean name explicitly - with no type matching semantics. - Note that this always points to a bean with that specific name, - no matter whether there is one or more beans of the given type. + Alternatively, consider using the + @Resource annotation on such an + overridden setter methods, defining the target bean name explicitly + - with no type matching semantics. Note that this always points to a + bean with that specific name, no matter whether there is one or more + beans of the given type. ... @Override @Resource("myDataSource") @@ -1263,8 +1245,8 @@ public final class HibernateTitleDaoTests { For class-level transaction configuration (i.e., setting the bean name for the transaction manager and the default rollback flag), see the @TransactionConfiguration entry - in the annotation support - section. + in the annotation + support section. There are several options for configuring transactions for individual test methods. If transactions are not enabled for the @@ -1318,9 +1300,9 @@ public final class HibernateTitleDaoTests { The following JUnit 4 based example displays a fictitious integration testing scenario highlighting several of the transaction-related annotations. Consult the annotation - support section of the reference manual for further information - and configuration examples. + linkend="integration-testing-annotations">annotation support + section of the reference manual for further information and + configuration examples. @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @@ -1635,7 +1617,6 @@ public class SimpleTest {
- @@ -1756,7 +1737,8 @@ public class HibernateClinicTests extends AbstractClinicTests { } pooling and transaction infrastructure. If you are deploying to a full-blown application server, you will probably use its connection pool (available through JNDI) and JTA implementation. Thus in production you - will use a JndiObjectFactoryBean for the + will use a JndiObjectFactoryBean / + <jee:jndi-lookup> for the DataSource and JtaTransactionManager. JNDI and JTA will not be available in out-of-container integration tests, so you should use a @@ -1777,56 +1759,57 @@ public class HibernateClinicTests extends AbstractClinicTests { }
Further Resources - This section contains links to further resources about testing in general. + This section contains links to further resources about testing in + general. - JUnit: - the Spring Framework's unit and integration test suite is written using - JUnit 3.8 and JUnit 4.5 as the testing framework. + JUnit: the Spring + Framework's unit and integration test suite is written using JUnit 3.8 + and JUnit 4.5 as the testing framework. - TestNG: - a testing framework inspired by JUnit 3.8 with added support - for Java 5 annotations, test groups, data-driven testing, distributed - testing, etc. + TestNG: a testing + framework inspired by JUnit 3.8 with added support for Java 5 + annotations, test groups, data-driven testing, distributed testing, + etc. - MockObjects.com: - a website dedicated to mock objects, a technique for improving the design - of code within Test-Driven Development. + MockObjects.com: a website + dedicated to mock objects, a technique for improving the design of + code within Test-Driven Development. - "Mock Objects": - article at Wikipedia. + "Mock + Objects": article at Wikipedia. - EasyMock: - the Spring Framework uses EasyMock extensively in its test suite. + EasyMock: the + Spring Framework uses EasyMock extensively in its test suite. - JMock: - a library that supports test-driven development of Java code - with mock objects. + JMock: a library that + supports test-driven development of Java code with mock + objects. - DbUnit: - a JUnit extension (also usable with Ant and Maven) targeted for database-driven - projects that, among other things, puts your database into a known state - between test runs. + DbUnit: a + JUnit extension (also usable with Ant and Maven) targeted for + database-driven projects that, among other things, puts your database + into a known state between test runs. - Grinder: - a Java load testing framework. + Grinder: a + Java load testing framework. -
- \ No newline at end of file + diff --git a/spring-framework-reference/src/web-integration.xml b/spring-framework-reference/src/web-integration.xml index 3796f434837..3e05e98fe10 100644 --- a/spring-framework-reference/src/web-integration.xml +++ b/spring-framework-reference/src/web-integration.xml @@ -1,489 +1,501 @@ - - +"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> + Integrating with other web frameworks
Introduction - - This chapter details Spring's integration with third party web frameworks - such as JSF, - Struts, - WebWork, and - Tapestry. - + + This chapter details Spring's integration with third party web + frameworks such as JSF, Struts, WebWork, and Tapestry. - - - One of the core value propositions of the Spring Framework is that of - enabling choice. In a general sense, Spring does not - force one to use or buy into any particular architecture, technology, or - methodology (although it certainly recommends some over others). This freedom - to pick and choose the architecture, technology, or methodology that is most - relevant to a developer and his or her development team is arguably most evident - in the web area, where Spring provides its own web framework - (Spring MVC), while at the same time providing integration - with a number of popular third party web frameworks. This allows one to continue - to leverage any and all of the skills one may have acquired in a - particular web framework such as Struts, while at the same time being able to - enjoy the benefits afforded by Spring in other areas such as data access, - declarative transaction management, and flexible configuration and application - assembly. - - - Having dispensed with the woolly sales patter (c.f. the previous paragraph), - the remainder of this chapter will concentrate upon the meaty details of - integrating your favourite web framework with Spring. One thing that is often - commented upon by developers coming to Java from other languages is the seeming - super-abundance of web frameworks available in Java... there are indeed a great - number of web frameworks in the Java space; in fact there are far too many to - cover with any semblance of detail in a single chapter. This chapter thus picks - four of the more popular web frameworks in Java, starting with the Spring - configuration that is common to all of the supported web frameworks, and then - detailing the specific integration options for each supported web framework. - - - - Please note that this chapter does not attempt to explain how to use any - of the supported web frameworks. For example, if you want to use Struts for - the presentation layer of your web application, the assumption is that you - are already familiar with Struts. If you need further details about any of - the supported web frameworks themselves, please do consult the section - entitled at the end of this chapter. - - + + + One of the core value propositions of the Spring Framework is that + of enabling choice. In a general sense, Spring does + not force one to use or buy into any particular architecture, technology, + or methodology (although it certainly recommends some over others). This + freedom to pick and choose the architecture, technology, or methodology + that is most relevant to a developer and his or her development team is + arguably most evident in the web area, where Spring provides its own web + framework (Spring MVC), while at the same time + providing integration with a number of popular third party web frameworks. + This allows one to continue to leverage any and all of the skills one may + have acquired in a particular web framework such as Struts, while at the + same time being able to enjoy the benefits afforded by Spring in other + areas such as data access, declarative transaction management, and + flexible configuration and application assembly. + + Having dispensed with the woolly sales patter (c.f. the previous + paragraph), the remainder of this chapter will concentrate upon the meaty + details of integrating your favourite web framework with Spring. One thing + that is often commented upon by developers coming to Java from other + languages is the seeming super-abundance of web frameworks available in + Java... there are indeed a great number of web frameworks in the Java + space; in fact there are far too many to cover with any semblance of + detail in a single chapter. This chapter thus picks four of the more + popular web frameworks in Java, starting with the Spring configuration + that is common to all of the supported web frameworks, and then detailing + the specific integration options for each supported web framework. + + Please note that this chapter does not attempt to explain + how to use any of the supported web frameworks. For example, if you want + to use Struts for the presentation layer of your web application, the + assumption is that you are already familiar with Struts. If you need + further details about any of the supported web frameworks themselves, + please do consult the section entitled at the end of this chapter. +
Common configuration - - Before diving into the integration specifics of each supported web framework, let - us first take a look at the Spring configuration that not - specific to any one web framework. (This section is equally applicable to Spring's - own web framework, Spring MVC.) - - - One of the concepts (for want of a better word) espoused by (Spring's) lightweight - application model is that of a layered architecture. Remember that in a 'classic' - layered architecture, the web layer is but one of many layers... it serves as one - of the entry points into a server side application, and it delegates to service - objects (facades) defined in a service layer to satisfy business specific (and - presentation-technology agnostic) use cases. In Spring, these service objects, - any other business-specific objects, data access objects, etc. exist in a - distinct 'business context', which contains no web or - presentation layer objects (presentation objects such as Spring MVC controllers - are typically configured in a distinct 'presentation context'). This section - details how one configures a Spring container (a - WebApplicationContext) that contains all of the - 'business beans' in one's application. - - - Onto specifics... all that one need do is to declare a - ContextLoaderListener - in the standard J2EE servlet web.xml file of one's web application, - and add a contextConfigLocation <context-param/> section - (in the same file) that defines which set of Spring XML cpnfiguration files to load. - - - Find below the <listener/> configuration: - - - org.springframework.web.context.ContextLoaderListener -]]> + + Before diving into the integration specifics of each supported web + framework, let us first take a look at the Spring configuration that + not specific to any one web framework. (This section + is equally applicable to Spring's own web framework, Spring MVC.) + + One of the concepts (for want of a better word) espoused by + (Spring's) lightweight application model is that of a layered + architecture. Remember that in a 'classic' layered architecture, the web + layer is but one of many layers... it serves as one of the entry points + into a server side application, and it delegates to service objects + (facades) defined in a service layer to satisfy business specific (and + presentation-technology agnostic) use cases. In Spring, these service + objects, any other business-specific objects, data access objects, etc. + exist in a distinct 'business context', which contains + no web or presentation layer objects (presentation + objects such as Spring MVC controllers are typically configured in a + distinct 'presentation context'). This section details how one configures + a Spring container (a WebApplicationContext) that + contains all of the 'business beans' in one's application. + + Onto specifics... all that one need do is to declare a ContextLoaderListener + in the standard J2EE servlet web.xml file of one's web + application, and add a contextConfigLocation + <context-param/> section (in the same file) that defines which set + of Spring XML cpnfiguration files to load. + + Find below the <listener/> configuration: + + <listener> + <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> +</listener> + - - Listeners were added to the Servlet API in version 2.3; listener startup order was - finally clarified in Servlet 2.4. If you have a Servlet 2.3 container, you can use the - ContextLoaderServlet - to achieve the same functionality in a 100% portable fashion (with respect to startup order). - + Listeners were added to the Servlet API in version 2.3; listener + startup order was finally clarified in Servlet 2.4. If you have a + Servlet 2.3 container, you can use the ContextLoaderServlet + to achieve the same functionality in a 100% portable fashion (with + respect to startup order). - - Find below the <context-param/> configuration: - - - contextConfigLocation - /WEB-INF/applicationContext*.xml -]]> - - If you don't specify the contextConfigLocation - context parameter, the ContextLoaderListener will look - for a file called /WEB-INF/applicationContext.xml to load. - Once the context files are loaded, Spring creates a - WebApplicationContext - object based on the bean definitions and stores it in the - ServletContext of one's web application. - - - All Java web frameworks are built on top of the Servlet API, and so one can - use the following code snippet to get access to this 'business context' - ApplicationContext created by the - ContextLoaderListener. - - - - The WebApplicationContextUtils - class is for convenience, so you don't have to remember the name of the - ServletContext attribute. Its getWebApplicationContext() - method will return null if an object doesn't exist under the - WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE key. Rather - than risk getting NullPointerExceptions in your application, it's - better to use the getRequiredWebApplicationContext() method. This - method throws an exception when the ApplicationContext is missing. - - - Once you have a reference to the WebApplicationContext, - you can retrieve beans by their name or type. Most developers retrieve beans - by name, then cast them to one of their implemented interfaces. - - - Fortunately, most of the frameworks in this section have simpler ways of looking up - beans. Not only do they make it easy to get beans from a Spring container, but they - also allow you to use dependency injection on their controllers. Each web framework - section has more detail on its specific integration strategies. - + + Find below the <context-param/> configuration: + + <context-param> + <param-name>contextConfigLocation</param-name> + <param-value>/WEB-INF/applicationContext*.xml</param-value> +</context-param> + + If you don't specify the contextConfigLocation + context parameter, the ContextLoaderListener will + look for a file called /WEB-INF/applicationContext.xml + to load. Once the context files are loaded, Spring creates a WebApplicationContext + object based on the bean definitions and stores it in the + ServletContext of one's web application. + + All Java web frameworks are built on top of the Servlet API, and so + one can use the following code snippet to get access to this 'business + context' ApplicationContext created by the + ContextLoaderListener. + + WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext); + + The WebApplicationContextUtils + class is for convenience, so you don't have to remember the name of the + ServletContext attribute. Its + getWebApplicationContext() method will return + null if an object doesn't exist under the + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + key. Rather than risk getting NullPointerExceptions + in your application, it's better to use the + getRequiredWebApplicationContext() method. This method + throws an exception when the ApplicationContext is + missing. + + Once you have a reference to the + WebApplicationContext, you can retrieve beans by + their name or type. Most developers retrieve beans by name, then cast them + to one of their implemented interfaces. + + Fortunately, most of the frameworks in this section have simpler + ways of looking up beans. Not only do they make it easy to get beans from + a Spring container, but they also allow you to use dependency injection on + their controllers. Each web framework section has more detail on its + specific integration strategies.
JavaServer Faces 1.1 and 1.2 - - JavaServer Faces (JSF) is the JCP's standard component-based, event-driven - web user interface framework. As of Java EE 5, it is an official part of - the Java EE umbrella. - - - For a popular JSF runtime as well as for popular JSF component libraries, check - out the Apache MyFaces project. - The MyFaces project also provides common JSF extensions such as - MyFaces Orchestra: - a Spring-based JSF extension that provides rich conversation scope support. - + + JavaServer Faces (JSF) is the JCP's standard component-based, + event-driven web user interface framework. As of Java EE 5, it is an + official part of the Java EE umbrella. + + For a popular JSF runtime as well as for popular JSF component + libraries, check out the Apache + MyFaces project. The MyFaces project also provides common JSF + extensions such as MyFaces Orchestra: a + Spring-based JSF extension that provides rich conversation scope + support. + - - Spring Web Flow 2.0 provides rich JSF support through its newly - established Spring Faces module, both for JSF-centric usage - (as described in this section) and for Spring-centric usage - (using JSF views within a Spring MVC dispatcher). Check out the - Spring Web Flow website - for details! - + Spring Web Flow 2.0 provides rich JSF support through its newly + established Spring Faces module, both for JSF-centric usage (as + described in this section) and for Spring-centric usage (using JSF views + within a Spring MVC dispatcher). Check out the Spring Web Flow + website for details! - - The key element in Spring's JSF integration is the JSF 1.1 - VariableResolver mechanism. On JSF 1.2, - Spring supports the ELResolver mechanism - as a next-generation version of JSF EL integration. - + + The key element in Spring's JSF integration is the JSF 1.1 + VariableResolver mechanism. On JSF 1.2, Spring + supports the ELResolver mechanism as a + next-generation version of JSF EL integration. +
DelegatingVariableResolver (JSF 1.1/1.2) - - The easiest way to integrate one's Spring middle-tier with one's - JSF web layer is to use the - - DelegatingVariableResolver class. To configure - this variable resolver in one's application, one will need to edit one's - faces-context.xml file. After the opening - <faces-config/> element, add an <application/> - element and a <variable-resolver/> element within it. - The value of the variable resolver should reference Spring's - DelegatingVariableResolver; for example: - - - org.springframework.web.jsf.DelegatingVariableResolver - - en - en - es - - messages - -]]> - - The DelegatingVariableResolver will first delegate value - lookups to the default resolver of the underlying JSF implementation, and - then to Spring's 'business context' WebApplicationContext. - This allows one to easily inject dependencies into one's JSF-managed beans. - - - Managed beans are defined in one's faces-config.xml - file. Find below an example where #{userManager} is a bean - that is retrieved from the Spring 'business context'. - - - userList - com.whatever.jsf.UserList - request - - userManager - #{userManager} - -]]> + + The easiest way to integrate one's Spring middle-tier with one's + JSF web layer is to use the + DelegatingVariableResolver class. To + configure this variable resolver in one's application, one will need to + edit one's faces-context.xml file. After the + opening <faces-config/> element, add an + <application/> element and a + <variable-resolver/> element within it. The + value of the variable resolver should reference Spring's + DelegatingVariableResolver; for example: + + <faces-config> + <application> + <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver> + <locale-config> + <default-locale>en</default-locale> + <supported-locale>en</supported-locale> + <supported-locale>es</supported-locale> + </locale-config> + <message-bundle>messages</message-bundle> + </application> +</faces-config> + + The DelegatingVariableResolver will first + delegate value lookups to the default resolver of the underlying JSF + implementation, and then to Spring's 'business context' + WebApplicationContext. This allows one to easily + inject dependencies into one's JSF-managed beans. + + Managed beans are defined in one's + faces-config.xml file. Find below an example where + #{userManager} is a bean that is retrieved from the + Spring 'business context'. + + <managed-bean> + <managed-bean-name>userList</managed-bean-name> + <managed-bean-class>com.whatever.jsf.UserList</managed-bean-class> + <managed-bean-scope>request</managed-bean-scope> + <managed-property> + <property-name>userManager</property-name> + <value>#{userManager}</value> + </managed-property> +</managed-bean>
+
SpringBeanVariableResolver (JSF 1.1/1.2) - - SpringBeanVariableResolver is a variant of - DelegatingVariableResolver. It delegates to the - Spring's 'business context' WebApplicationContext - first, then to the default resolver of the - underlying JSF implementation. This is useful in particular when - using request/session-scoped beans with special Spring resolution rules, - e.g. Spring FactoryBean implementations. - - - Configuration-wise, simply define SpringBeanVariableResolver - in your faces-context.xml file: - - - - org.springframework.web.jsf.SpringBeanVariableResolver + + SpringBeanVariableResolver is a variant of + DelegatingVariableResolver. It delegates to the + Spring's 'business context' WebApplicationContext + first, then to the default resolver of the + underlying JSF implementation. This is useful in particular when using + request/session-scoped beans with special Spring resolution rules, e.g. + Spring FactoryBean + implementations. + + Configuration-wise, simply define + SpringBeanVariableResolver in your + faces-context.xml file: + + <faces-config> + <application> + <variable-resolver>org.springframework.web.jsf.SpringBeanVariableResolver</variable-resolver> ... - -]]> + </application> +</faces-config>
+
SpringBeanFacesELResolver (JSF 1.2+) - - SpringBeanFacesELResolver is a JSF 1.2 compliant - ELResolver implementation, integrating with - the standard Unified EL as used by JSF 1.2 and JSP 2.1. Like - SpringBeanVariableResolver, it delegates to the - Spring's 'business context' WebApplicationContext - first, then to the default resolver of the - underlying JSF implementation. - - - Configuration-wise, simply define SpringBeanFacesELResolver - in your JSF 1.2 faces-context.xml file: - - - - org.springframework.web.jsf.el.SpringBeanFacesELResolver + + SpringBeanFacesELResolver is a JSF 1.2 + compliant ELResolver implementation, integrating + with the standard Unified EL as used by JSF 1.2 and JSP 2.1. Like + SpringBeanVariableResolver, it delegates to the + Spring's 'business context' WebApplicationContext + first, then to the default resolver of the + underlying JSF implementation. + + Configuration-wise, simply define + SpringBeanFacesELResolver in your JSF 1.2 + faces-context.xml file: + + <faces-config> + <application> + <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> ... - -]]> + </application> +</faces-config>
+
FacesContextUtils - - A custom VariableResolver works well when mapping - one's properties to beans in faces-config.xml, but at times - one may need to grab a bean explicitly. The - - FacesContextUtils class makes this easy. It is - similar to WebApplicationContextUtils, except that it - takes a FacesContext parameter rather than a - ServletContext parameter. - - + + A custom VariableResolver works + well when mapping one's properties to beans in + faces-config.xml, but at times one may need to grab + a bean explicitly. The + FacesContextUtils class makes this easy. + It is similar to WebApplicationContextUtils, + except that it takes a FacesContext parameter + rather than a ServletContext parameter. + + ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
Apache Struts 1.x and 2.x - - Struts is the - de facto web framework for Java applications, mainly - because it was one of the first to be released (June 2001). Invented by - Craig McClanahan, Struts is an open source project hosted by the Apache - Software Foundation. At the time, it greatly simplified the JSP/Servlet - programming paradigm and won over many developers who were using - proprietary frameworks. It simplified the programming model, it was open - source (and thus free as in beer), and it had a large community, which allowed - the project to grow and become popular among Java web developers. - + + Struts is the + de facto web framework for Java applications, mainly + because it was one of the first to be released (June 2001). Invented by + Craig McClanahan, Struts is an open source project hosted by the Apache + Software Foundation. At the time, it greatly simplified the JSP/Servlet + programming paradigm and won over many developers who were using + proprietary frameworks. It simplified the programming model, it was open + source (and thus free as in beer), and it had a large community, which + allowed the project to grow and become popular among Java web + developers. + - - The following section discusses Struts 1 a.k.a. "Struts Classic". - - - Struts 2 is effectively a different product - a successor of - WebWork 2.2 (as discussed in ), - carrying the Struts brand now. Check out the Struts 2 - Spring Plugin - for the built-in Spring integration shipped with Struts 2. - In general, Struts 2 is closer to WebWork 2.2 than to Struts 1 - in terms of its Spring integration implications. - + The following section discusses Struts 1 a.k.a. "Struts + Classic". + + Struts 2 is effectively a different product - a successor of + WebWork 2.2 (as discussed in ), carrying the + Struts brand now. Check out the Struts 2 Spring + Plugin for the built-in Spring integration shipped with Struts + 2. In general, Struts 2 is closer to WebWork 2.2 than to Struts 1 in + terms of its Spring integration implications. - - To integrate your Struts 1.x application with Spring, you have two options: - + + To integrate your Struts 1.x application with Spring, you have two + options: + - - Configure Spring to manage your Actions as beans, using the - ContextLoaderPlugin, and set their - dependencies in a Spring context file. - + Configure Spring to manage your Actions as beans, using the + ContextLoaderPlugin, and set their dependencies + in a Spring context file. + - - Subclass Spring's ActionSupport - classes and grab your Spring-managed beans explicitly using - a getWebApplicationContext() method. - + Subclass Spring's ActionSupport classes + and grab your Spring-managed beans explicitly using a + getWebApplicationContext() method. +
ContextLoaderPlugin - - The ContextLoaderPlugin - is a Struts 1.1+ plug-in that loads a Spring context file for the Struts - ActionServlet. This context refers to the root - WebApplicationContext (loaded by the - ContextLoaderListener) as its parent. The default - name of the context file is the name of the mapped servlet, plus - -servlet.xml. If ActionServlet - is defined in web.xml as - <servlet-name>action</servlet-name>, the - default is /WEB-INF/action-servlet.xml. - - - To configure this plug-in, add the following XML to the plug-ins section near - the bottom of your struts-config.xml file: - - ]]> - - The location of the context configuration files can be customized using the - 'contextConfigLocation' property. - - - -]]> - - It is possible to use this plugin to load all your context files, which can be - useful when using testing tools like StrutsTestCase. StrutsTestCase's - MockStrutsTestCase won't initialize Listeners on startup - so putting all your context files in the plugin is a workaround. (A - - bug has been filed for this issue, but has been closed as 'Wont Fix'). - - - After configuring this plug-in in struts-config.xml, you can - configure your Action to be managed by Spring. Spring (1.1.3+) - provides two ways to do this: - + + The ContextLoaderPlugin + is a Struts 1.1+ plug-in that loads a Spring context file for the Struts + ActionServlet. This context refers to the root + WebApplicationContext (loaded by the + ContextLoaderListener) as its parent. The default + name of the context file is the name of the mapped servlet, plus + -servlet.xml. If + ActionServlet is defined in web.xml as + <servlet-name>action</servlet-name>, the + default is /WEB-INF/action-servlet.xml. + + To configure this plug-in, add the following XML to the plug-ins + section near the bottom of your struts-config.xml + file: + + <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"/> + + The location of the context configuration files can be customized + using the 'contextConfigLocation' property. + + <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> + <set-property property="contextConfigLocation" + value="/WEB-INF/action-servlet.xml,/WEB-INF/applicationContext.xml"/> +</plug-in> + + It is possible to use this plugin to load all your context files, + which can be useful when using testing tools like StrutsTestCase. + StrutsTestCase's MockStrutsTestCase won't + initialize Listeners on startup so putting all your context files in the + plugin is a workaround. (A + bug has been filed for this issue, but has been closed as 'Wont + Fix'). + + After configuring this plug-in in + struts-config.xml, you can configure your + Action to be managed by Spring. Spring (1.1.3+) + provides two ways to do this: + - - Override Struts' default RequestProcessor - with Spring's DelegatingRequestProcessor. - + Override Struts' default + RequestProcessor with Spring's + DelegatingRequestProcessor. + - - Use the DelegatingActionProxy class - in the type attribute of your - <action-mapping>. - + Use the DelegatingActionProxy class in + the type attribute of your + <action-mapping>. - - Both of these methods allow you to manage your Actions and - their dependencies in the action-servlet.xml file. - The bridge between the Action in struts-config.xml - and action-servlet.xml is built with the - action-mapping's "path" and the bean's "name". If you have the - following in your struts-config.xml file: - - ]]> - - You must define that Action's bean with the "/users" name in - action-servlet.xml: - - ]]> + + Both of these methods allow you to manage your Actions and their + dependencies in the action-servlet.xml file. The + bridge between the Action in struts-config.xml and + action-servlet.xml is built with the + action-mapping's "path" and the bean's "name". If you have the following + in your struts-config.xml file: + + <action path="/users" .../> + + You must define that Action's bean with the "/users" name in + action-servlet.xml: + + <bean name="/users" .../> +
DelegatingRequestProcessor - - To configure the - DelegatingRequestProcessor in your - struts-config.xml file, override the "processorClass" - property in the <controller> element. These lines follow the - <action-mapping> element. - - - -]]> - - After adding this setting, your Action will automatically be - looked up in Spring's context file, no matter what the type. In fact, - you don't even need to specify a type. Both of the following snippets - will work: - - -]]> - - If you're using Struts' modules feature, - your bean names must contain the module prefix. For example, an action - defined as <action path="/user"/> with module - prefix "admin" requires a bean name with - <bean name="/admin/user"/>. - + + To configure the + DelegatingRequestProcessor in your + struts-config.xml file, override the + "processorClass" property in the <controller> element. These + lines follow the <action-mapping> element. + + <controller> + <set-property property="processorClass" + value="org.springframework.web.struts.DelegatingRequestProcessor"/> +</controller> + + After adding this setting, your Action will automatically be + looked up in Spring's context file, no matter what the type. In fact, + you don't even need to specify a type. Both of the following snippets + will work: + + <action path="/user" type="com.whatever.struts.UserAction"/> +<action path="/user"/> + + If you're using Struts' modules feature, + your bean names must contain the module prefix. For example, an action + defined as <action path="/user"/> with module + prefix "admin" requires a bean name with <bean + name="/admin/user"/>. + - - If you are using Tiles in your Struts application, you must configure your - <controller> with the - DelegatingTilesRequestProcessor - instead. - + If you are using Tiles in your Struts application, you must + configure your <controller> with the DelegatingTilesRequestProcessor + instead.
+
DelegatingActionProxy - - If you have a custom RequestProcessor and - can't use the DelegatingRequestProcessor or - DelegatingTilesRequestProcessor approaches, you can - use the - DelegatingActionProxy as the type in your - action-mapping. - - - - -]]> - - The bean definition in action-servlet.xml - remains the same, whether you use a custom RequestProcessor - or the DelegatingActionProxy. - - - If you define your Action in a context file, the - full feature set of Spring's bean container will be available for it: - dependency injection as well as the option to instantiate a new - Action instance for each request. To activate the latter, - add scope="prototype" to your Action's bean definition. - - ]]> + + If you have a custom RequestProcessor and + can't use the DelegatingRequestProcessor or + DelegatingTilesRequestProcessor approaches, you + can use the + DelegatingActionProxy as the type in + your action-mapping. + + <action path="/user" type="org.springframework.web.struts.DelegatingActionProxy" + name="userForm" scope="request" validate="false" parameter="method"> + <forward name="list" path="/userList.jsp"/> + <forward name="edit" path="/userForm.jsp"/> +</action> + + The bean definition in action-servlet.xml + remains the same, whether you use a custom + RequestProcessor or the + DelegatingActionProxy. + + If you define your Action in a context + file, the full feature set of Spring's bean container will be + available for it: dependency injection as well as the option to + instantiate a new Action instance for each + request. To activate the latter, add + scope="prototype" to your Action's bean + definition. + + <bean name="/user" scope="prototype" autowire="byName" + class="org.example.web.UserAction"/>
+
ActionSupport Classes - - As previously mentioned, you can retrieve the - WebApplicationContext from the ServletContext - using the WebApplicationContextUtils class. An - easier way is to extend Spring's Action classes for - Struts. For example, instead of subclassing Struts' - Action class, you can subclass Spring's - - ActionSupport class. - - - The ActionSupport class provides additional - convenience methods, like getWebApplicationContext(). - Below is an example of how you might use this in an Action: - - As previously mentioned, you can retrieve the + WebApplicationContext from the + ServletContext using the + WebApplicationContextUtils class. An easier way + is to extend Spring's Action classes for Struts. + For example, instead of subclassing Struts' + Action class, you can subclass Spring's + ActionSupport class. + + The ActionSupport class provides additional + convenience methods, like + getWebApplicationContext(). Below is an example of + how you might use this in an Action: + + public class UserAction extends DispatchActionSupport { public ActionForward execute(ActionMapping mapping, ActionForm form, @@ -497,257 +509,272 @@ // talk to manager for business logic return mapping.findForward("success"); } -}]]> - - Spring includes subclasses for all of the standard Struts Actions - - the Spring versions merely have Support appended to the name: - - ActionSupport, - DispatchActionSupport, - LookupDispatchActionSupport and - MappingDispatchActionSupport. - - +} - - The recommended strategy is to use the approach that best suits + Spring includes subclasses for all of the standard Struts Actions + - the Spring versions merely have Support appended + to the name: + + ActionSupport, + + + + DispatchActionSupport, + + + + LookupDispatchActionSupport + and + + + + MappingDispatchActionSupport. + + + + The recommended strategy is to use the approach that best suits your project. Subclassing makes your code more readable, and you know exactly how your dependencies are resolved. However, using the ContextLoaderPlugin allow you to easily add new dependencies in your context XML file. Either way, Spring provides some - nice options for integrating the two frameworks. - + nice options for integrating the two frameworks.
WebWork 2.x - - From the WebWork homepage... - + + From the WebWork + homepage... + - - WebWork is a Java web-application development framework. It is built - specifically with developer productivity and code simplicity in mind, - providing robust support for building reusable UI templates, such as form - controls, UI themes, internationalization, dynamic form parameter mapping - to JavaBeans, robust client and server side validation, and much more. - + WebWork is a Java web-application development framework. It is + built specifically with developer productivity and code simplicity in + mind, providing robust support for building reusable UI templates, such + as form controls, UI themes, internationalization, dynamic form + parameter mapping to JavaBeans, robust client and server side + validation, and much more. - - WebWork is (in the opinion of this author) a very clean, elegant web framework. - Its architecture and key concepts are not only very easy to understand, it has - a rich tag library, nicely decoupled validation, and it is (again, in the opinion - of this author) quite easy to be productive in next to no time at all (the - documentation and tutorials are pretty good too). - - - One of the key enablers in WebWork's technology stack is - an IoC container - to manage Webwork Actions, handle the "wiring" of business objects, etc. - Prior to WebWork version 2.2, WebWork used its own proprietary IoC container - (and provided integration points so that one could integrate an IoC container - such as Springs into the mix). However, as of WebWork version 2.2, the default - IoC container that is used within WebWork is Spring. This - is obviously great news if one is a Spring developer, because it means that one - is immediately familiar with the basics of IoC configuration, idioms and suchlike - within WebWork. - - - Now in the interests of adhering to the DRY (Dont Repeat Yourself) principle, it - would be foolish to writeup the Spring-WebWork integration in light of the fact that - the WebWork team have already written such a writeup. Please do consult the - Spring-WebWork integration page - on the - WebWork wiki - for the full lowdown. - - - Note that the Spring-WebWork integration code was developed (and continues - to be maintained and improved) by the WebWork developers themselves, so in the - first instance please do refer to the WebWork site and forums if you are having - issues with the integration. Do feel free to post comments and queries regarding - the Spring-WebWork integration on the - Spring support forums - too. - + + WebWork is (in the opinion of this author) a very clean, elegant web + framework. Its architecture and key concepts are not only very easy to + understand, it has a rich tag library, nicely decoupled validation, and it + is (again, in the opinion of this author) quite easy to be productive in + next to no time at all (the documentation and tutorials are pretty good + too). + + One of the key enablers in WebWork's technology stack is an + IoC container to manage Webwork Actions, handle the "wiring" of + business objects, etc. Prior to WebWork version 2.2, WebWork used its own + proprietary IoC container (and provided integration points so that one + could integrate an IoC container such as Springs into the mix). However, + as of WebWork version 2.2, the default IoC container that is used within + WebWork is Spring. This is obviously great news if + one is a Spring developer, because it means that one is immediately + familiar with the basics of IoC configuration, idioms and suchlike within + WebWork. + + Now in the interests of adhering to the DRY (Dont Repeat Yourself) + principle, it would be foolish to writeup the Spring-WebWork integration + in light of the fact that the WebWork team have already written such a + writeup. Please do consult the Spring-WebWork + integration page on the WebWork wiki + for the full lowdown. + + Note that the Spring-WebWork integration code was developed (and + continues to be maintained and improved) by the WebWork developers + themselves, so in the first instance please do refer to the WebWork site + and forums if you are having issues with the integration. Do feel free to + post comments and queries regarding the Spring-WebWork integration on the + Spring + support forums too.
Tapestry 3.x and 4.x - - From the Tapestry homepage... - + + From the Tapestry + homepage... + - - Tapestry is an open-source framework for creating dynamic, robust, highly - scalable web applications in Java. Tapestry complements and builds upon - the standard Java Servlet API, and so it works in any servlet container or - application server. - + Tapestry is an open-source framework for creating dynamic, + robust, highly scalable web applications in Java. Tapestry complements + and builds upon the standard Java Servlet API, and so it works in any + servlet container or application server. - - While Spring has its own powerful web layer, there - are a number of unique advantages to building a J2EE application using a - combination of Tapestry for the web user interface and the Spring container - for the lower layers. This section of the web integration chapter attempts - to detail a few best practices for combining these two frameworks. - - - A typical layered J2EE application built with Tapestry - and Spring will consist of a top user interface (UI) layer built with Tapestry, - and a number of lower layers, all wired together by one or more Spring containers. - Tapestry's own reference documentation contains the following snippet of best - practice advice. (Text that the author of this Spring section has added is - contained within [] brackets.) - + + While Spring has its own powerful web + layer, there are a number of unique advantages to building a J2EE + application using a combination of Tapestry for the web user interface and + the Spring container for the lower layers. This section of the web + integration chapter attempts to detail a few best practices for combining + these two frameworks. + + A typical layered J2EE application built with + Tapestry and Spring will consist of a top user interface (UI) layer built + with Tapestry, and a number of lower layers, all wired together by one or + more Spring containers. Tapestry's own reference documentation contains + the following snippet of best practice advice. (Text that the author of + this Spring section has added is contained within [] + brackets.) + - - A very succesful design pattern in Tapestry is to keep pages and components - very simple, and delegate as much logic as - possible out to HiveMind [or Spring, or whatever] services. Listener methods - should ideally do little more than marshall together the correct information - and pass it over to a service. - + A very succesful design pattern in Tapestry is to keep pages + and components very simple, and delegate as much logic as possible out to + HiveMind [or Spring, or whatever] services. Listener methods should + ideally do little more than marshall together the correct information + and pass it over to a service. - - The key question then is... how does one supply Tapestry pages with collaborating - services? The answer, ideally, is that one would want to dependency inject those - services directly into one's Tapestry pages. In Tapestry, one can effect this - dependency injection by a variety of means... - This section is only going to enumerate the dependency injection means afforded - by Spring. The real beauty of the rest of this Spring-Tapestry integration is that - the elegant and flexible design of Tapestry itself makes doing this dependency - injection of Spring-managed beans a cinch. (Another nice thing is that this - Spring-Tapestry integration code was written - and continues to be maintained - - by the Tapestry creator - Howard M. Lewis Ship, - so hats off to him for what is really some silky smooth integration). - + + The key question then is... how does one supply Tapestry pages with + collaborating services? The answer, ideally, is that one would want to + dependency inject those services directly into one's Tapestry pages. In + Tapestry, one can effect this dependency injection by a variety of + means... This section is only going to enumerate the dependency injection + means afforded by Spring. The real beauty of the rest of this + Spring-Tapestry integration is that the elegant and flexible design of + Tapestry itself makes doing this dependency injection of Spring-managed + beans a cinch. (Another nice thing is that this Spring-Tapestry + integration code was written - and continues to be maintained - by the + Tapestry creator Howard M. + Lewis Ship, so hats off to him for what is really some silky + smooth integration). +
Injecting Spring-managed beans - - Assume we have the following simple Spring container definition (in the - ubiquitous XML format): - - - + + Assume we have the following simple Spring container definition + (in the ubiquitous XML format): + + <?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:jee="http://www.springframework.org/schema/jee" + xsi:schemaLocation=" +http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd +http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd"> - - - - - +<beans> + <!-- the DataSource --> + <jee:jndi-lookup id="dataSource" jndi-name="java:DefaultDS"/> - - - + <bean id="hibSessionFactory" + class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> + <property name="dataSource" ref="dataSource"/> + </bean> - + <bean id="transactionManager" + class="org.springframework.transaction.jta.JtaTransactionManager"/> - - - + <bean id="mapper" + class="com.whatever.dataaccess.mapper.hibernate.MapperImpl"> + <property name="sessionFactory" ref="hibSessionFactory"/> + </bean> - - - - - - - - - - - + <!-- (transactional) AuthenticationService --> + <bean id="authenticationService" + class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> + <property name="transactionManager" ref="transactionManager"/> + <property name="target"> + <bean class="com.whatever.services.service.user.AuthenticationServiceImpl"> + <property name="mapper" ref="mapper"/> + </bean> + </property> + <property name="proxyInterfacesOnly" value="true"/> + <property name="transactionAttributes"> + <value> *=PROPAGATION_REQUIRED - - - + </value> + </property> + </bean> - - - - - - - - - - - + <!-- (transactional) UserService --> + <bean id="userService" + class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> + <property name="transactionManager" ref="transactionManager"/> + <property name="target"> + <bean class="com.whatever.services.service.user.UserServiceImpl"> + <property name="mapper" ref="mapper"/> + </bean> + </property> + <property name="proxyInterfacesOnly" value="true"/> + <property name="transactionAttributes"> + <value> *=PROPAGATION_REQUIRED - - - + </value> + </property> + </bean> - ]]> - - Inside the Tapestry application, the above bean definitions need to - be loaded into a Spring container, - and any relevant Tapestry pages need to be supplied (injected) with the - authenticationService and - userService beans, which implement the - AuthenticationService and - UserService interfaces, respectively. - - - At this point, the application context is available to a web - application by calling Spring's static utility function - WebApplicationContextUtils.getApplicationContext(servletContext), - where servletContext is the standard ServletContext - from the J2EE Servlet specification. As such, one simple mechanism for - a page to get an instance of the UserService, - for example, would be with code such as: - - + + Inside the Tapestry application, the above bean definitions need + to be loaded into a Spring + container, and any relevant Tapestry pages need to be supplied + (injected) with the authenticationService and + userService beans, which implement the + AuthenticationService and + UserService interfaces, + respectively. + + At this point, the application context is available to a web + application by calling Spring's static utility function + WebApplicationContextUtils.getApplicationContext(servletContext), + where servletContext is the standard + ServletContext from the J2EE Servlet + specification. As such, one simple mechanism for a page to get an + instance of the UserService, for example, + would be with code such as: + + WebApplicationContext appContext = WebApplicationContextUtils.getApplicationContext( getRequestCycle().getRequestContext().getServlet().getServletContext()); UserService userService = (UserService) appContext.getBean("userService"); -]]>... some code which uses UserService - - This mechanism does work... having said that, it can be made a - lot less verbose by encapsulating most of the functionality in a - method in the base class for the page or component. However, in - some respects it goes against the IoC principle; ideally you would like the page to - not have to ask the context for a specific bean by name, and in - fact, the page would ideally not know about the context at all. - - - Luckily, there is a mechanism to allow this. We rely upon the - fact that Tapestry already has a mechanism to declaratively add - properties to a page, and it is in fact the preferred approach to - manage all properties on a page in this declarative fashion, so that - Tapestry can properly manage their lifecycle as part of the page and - component lifecycle. - +... some code which uses UserService + + This mechanism does work... having said that, it can be made a lot + less verbose by encapsulating most of the functionality in a method in + the base class for the page or component. However, in some respects it + goes against the IoC principle; ideally you would like the page to not + have to ask the context for a specific bean by name, and in fact, the + page would ideally not know about the context at all. + + Luckily, there is a mechanism to allow this. We rely upon the fact + that Tapestry already has a mechanism to declaratively add properties to + a page, and it is in fact the preferred approach to manage all + properties on a page in this declarative fashion, so that Tapestry can + properly manage their lifecycle as part of the page and component + lifecycle. + - - This next section is applicable to Tapestry 3.x. - If you are using Tapestry version 4.x, please consult the section - entitled . - + This next section is applicable to Tapestry 3.x. If you are + using Tapestry version 4.x, please consult the section entitled . +
Dependency Injecting Spring Beans into Tapestry pages - - First we need to make the ApplicationContext - available to the Tapestry page or Component without having to have the - ServletContext; this is because at the stage in the - page's/component's lifecycle when we need to access the - ApplicationContext, the - ServletContext won't be easily available to the - page, so we can't use - WebApplicationContextUtils.getApplicationContext(servletContext) - directly. One way is by defining a custom version of the Tapestry - IEngine which exposes this for us: - - First we need to make the + ApplicationContext available to the Tapestry + page or Component without having to have the + ServletContext; this is because at the stage in + the page's/component's lifecycle when we need to access the + ApplicationContext, the + ServletContext won't be easily available to the + page, so we can't use + WebApplicationContextUtils.getApplicationContext(servletContext) + directly. One way is by defining a custom version of the Tapestry + IEngine which exposes this for + us: + + package com.whatever.web.xportal; import ... @@ -771,104 +798,106 @@ public class MyEngine extends org.apache.tapestry.engine.BaseEngine { global.put(APPLICATION_CONTEXT_KEY, ac); } } -}]]> - - This engine class places the Spring Application Context as - an attribute called "appContext" in this Tapestry app's 'Global' - object. Make sure to register the fact that this special IEngine - instance should be used for this Tapestry application, with an entry - in the Tapestry application definition file. For example: - - file: xportal.application: - + + This engine class places the Spring Application Context as an + attribute called "appContext" in this Tapestry app's 'Global' object. + Make sure to register the fact that this special IEngine instance + should be used for this Tapestry application, with an entry in the + Tapestry application definition file. For example: + + file: xportal.application: +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE application PUBLIC "-//Apache Software Foundation//Tapestry Specification 3.0//EN" - "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd"> - -]]> + engine-class="com.whatever.web.xportal.MyEngine"> +</application>
+
Component definition files - - Now in our page or component definition file (*.page or *.jwc), - we simply add property-specification elements to grab the beans we - need out of the ApplicationContext, - and create page or component properties for them. For example: - - + + Now in our page or component definition file (*.page or *.jwc), + we simply add property-specification elements to grab the beans we + need out of the ApplicationContext, and + create page or component properties for them. For example: + + <property-specification name="userService" + type="com.whatever.services.service.user.UserService"> global.appContext.getBean("userService") - - + </property-specification> + <property-specification name="authenticationService" + type="com.whatever.services.service.user.AuthenticationService"> global.appContext.getBean("authenticationService") - ]]> - - The OGNL expression inside the property-specification specifies the - initial value for the property, as a bean obtained from the context. - The entire page definition might look like this: - - - + + The OGNL expression inside the property-specification specifies + the initial value for the property, as a bean obtained from the + context. The entire page definition might look like this: + + <?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE page-specification PUBLIC "-//Apache Software Foundation//Tapestry Specification 3.0//EN" - "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd"> + "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd"> - +<page-specification class="com.whatever.web.xportal.pages.Login"> - - - - - + <property-specification name="username" type="java.lang.String"/> + <property-specification name="password" type="java.lang.String"/> + <property-specification name="error" type="java.lang.String"/> + <property-specification name="callback" type="org.apache.tapestry.callback.ICallback" persistent="yes"/> + <property-specification name="userService" + type="com.whatever.services.service.user.UserService"> global.appContext.getBean("userService") - - + </property-specification> + <property-specification name="authenticationService" + type="com.whatever.services.service.user.AuthenticationService"> global.appContext.getBean("authenticationService") - + </property-specification> - + <bean name="delegate" class="com.whatever.web.xportal.PortalValidationDelegate"/> - - - - + <bean name="validator" class="org.apache.tapestry.valid.StringValidator" lifecycle="page"> + <set-property name="required" expression="true"/> + <set-property name="clientScriptingEnabled" expression="true"/> + </bean> - - - - - + <component id="inputUsername" type="ValidField"> + <static-binding name="displayName" value="Username"/> + <binding name="value" expression="username"/> + <binding name="validator" expression="beans.validator"/> + </component> - - - - - - + <component id="inputPassword" type="ValidField"> + <binding name="value" expression="password"/> + <binding name="validator" expression="beans.validator"/> + <static-binding name="displayName" value="Password"/> + <binding name="hidden" expression="true"/> + </component> -]]> +</page-specification>
+
Adding abstract accessors - - Now in the Java class definition for the page or component - itself, all we need to do is add an abstract getter method - for the properties we have defined (in order to be able to - access the properties). - - Now in the Java class definition for the page or component + itself, all we need to do is add an abstract getter method for the + properties we have defined (in order to be able to access the + properties). + + // our UserService implementation; will come from page definition public abstract UserService getUserService(); // our AuthenticationService implementation; will come from page definition -public abstract AuthenticationService getAuthenticationService();]]> - - For the sake of completeness, the entire Java class, for a - login page in this example, might look like this: - - + + For the sake of completeness, the entire Java class, for a login + page in this example, might look like this: + + package com.whatever.web.xportal.pages; /** * Allows the user to login, by providing username and password. @@ -910,7 +939,7 @@ public abstract class Login extends BasePage implements ErrorProperty, PageRende /** * Attempts to login. - *

+ * <p> * If the user name is not known, or the password is invalid, then an error * message is displayed. **/ @@ -980,31 +1009,33 @@ public abstract class Login extends BasePage implements ErrorProperty, PageRende setUsername(getRequestCycle().getRequestContext().getCookieValue(COOKIE_NAME)); } } -}]]> +}

+
- Dependency Injecting Spring Beans into Tapestry pages - Tapestry 4.x style - - Effecting the dependency injection of Spring-managed beans into Tapestry - pages in Tapestry version 4.x is so much simpler. - All that is needed is a single - add-on library, - and some (small) amount of (essentially boilerplate) configuration. - Simply package and deploy this library with the (any of the) other - libraries required by your web application (typically in - WEB-INF/lib). - - - You will then need to create and expose the Spring container using the - method detailed previously. - You can then inject Spring-managed beans into Tapestry very easily; if - we are using Java 5, consider the Login page from above: - we simply need to annotate the appropriate getter methods - in order to dependency inject the Spring-managed userService - and authenticationService objects (lots of the class - definition has been elided for clarity)... - - Dependency Injecting Spring Beans into Tapestry pages - + Tapestry 4.x style + + Effecting the dependency injection of Spring-managed beans into + Tapestry pages in Tapestry version 4.x is so much + simpler. All that is needed is a single add-on + library, and some (small) amount of (essentially boilerplate) + configuration. Simply package and deploy this library with the (any of + the) other libraries required by your web application (typically in + WEB-INF/lib). + + You will then need to create and expose the Spring container + using the method detailed + previously. You can then inject Spring-managed beans into + Tapestry very easily; if we are using Java 5, consider the + Login page from above: we simply need to + annotate the appropriate getter methods in order to dependency inject + the Spring-managed userService and + authenticationService objects (lots of the class + definition has been elided for clarity)... + + package com.whatever.web.xportal.pages; public abstract class Login extends BasePage implements ErrorProperty, PageRenderListener { @@ -1014,79 +1045,88 @@ public abstract class Login extends BasePage implements ErrorProperty, PageRende @InjectObject("spring:authenticationService") public abstract AuthenticationService getAuthenticationService(); -}]]> - - We are almost done... all that remains is the HiveMind configuration that exposes the - Spring container stored in the ServletContext as a - HiveMind service; for example: - - +} - We are almost done... all that remains is the HiveMind + configuration that exposes the Spring container stored in the + ServletContext as a HiveMind service; + for example: + + <?xml version="1.0"?> +<module id="com.javaforge.tapestry.spring" version="0.1.1"> + + <service-point id="SpringApplicationInitializer" interface="org.apache.tapestry.services.ApplicationInitializer" - visibility="private"> - - - - - - + visibility="private"> + <invoke-factory> + <construct class="com.javaforge.tapestry.spring.SpringApplicationInitializer"> + <set-object property="beanFactoryHolder" + value="service:hivemind.lib.DefaultSpringBeanFactoryHolder" /> + </construct> + </invoke-factory> + </service-point> - - - - + <!-- Hook the Spring setup into the overall application initialization. --> + <contribution + configuration-id="tapestry.init.ApplicationInitializers"> + <command id="spring-context" + object="service:SpringApplicationInitializer" /> + </contribution> -]]> - - If you are using Java 5 (and thus have access to annotations), then - that really is it. - - - If you are not using Java 5, then one obviously doesn't annotate one's - Tapestry page classes with annotations; instead, one simply uses - good old fashioned XML to declare the dependency injection; for example, - inside the .page or .jwc file - for the Login page (or component): - - -]]> +</module> + + If you are using Java 5 (and thus have access to annotations), + then that really is it. + + If you are not using Java 5, then one obviously doesn't annotate + one's Tapestry page classes with annotations; instead, one simply uses + good old fashioned XML to declare the dependency injection; for + example, inside the .page or + .jwc file for the Login page + (or component): + + <inject property="userService" object="spring:userService"/> +<inject property="authenticationService" object="spring:authenticationService"/>
- - In this example, we've managed to allow service beans defined in - a Spring container to be provided to the Tapestry page in a declarative - fashion. The page class does not know where the service implementations - are coming from, and in fact it is easy to slip in another implementation, - for example, during testing. This inversion of control is one of the - prime goals and benefits of the Spring Framework, and we have managed - to extend it all the way up the J2EE stack in this Tapestry application. - + + In this example, we've managed to allow service beans defined in a + Spring container to be provided to the Tapestry page in a declarative + fashion. The page class does not know where the service implementations + are coming from, and in fact it is easy to slip in another implementation, + for example, during testing. This inversion of control is one of the prime + goals and benefits of the Spring Framework, and we have managed to extend + it all the way up the J2EE stack in this Tapestry application.
Further Resources - - Find below links to further resources about the various web frameworks - described in this chapter. - + + Find below links to further resources about the various web + frameworks described in this chapter. + - The JSF homepage + The JSF + homepage + - The Struts homepage + The Struts + homepage + - The WebWork homepage + The WebWork + homepage + - The Tapestry homepage + The Tapestry + homepage
-