7 Developing Spring-Based Applications for Oracle WebLogic Server

Included with WebLogic Server is a sample application, called MedRec (Spring Version), called MedRec-Spring for short. The sample application is based on the WebLogic Server J2EE-based Avitek Medical Records sample application (MedRec). In MedRec-Spring, the J2EE-based Medrec's components are replaced with Spring components, as described in the following sections:

  1. Configure Spring Inversion of Control.

  2. Enable the Spring Web Services Client Service. Spring offers a JAX-WC factory to produce a proxy for Web Services

  3. Make JMS Services Available to the Application at Runtime.

  4. Use JPA Data Access.

  5. Use the Spring Transaction Abstraction Layer for Transaction Management.

The sample code in the following sections are from MedRec-Spring.

Note:

MedRec-Spring is not installed by default when you install WebLogic Server. You must choose Custom installation, then select Server Examples from the Choose Products and Component page.

If you have already installed WebLogic Server, rerun the installer, select the Middleware home where WebLogic Server is installed, choose Custom installation, then select Server Examples from the Choose Products and Component page.

Included with Medrec-Spring is documentation which discusses its design and implementation. That documentation is available at WL_HOME\samples\server\docs\. You can display it from the Windows Start Menu as follows: Start > Programs > Oracle WebLogic > WebLogic Server > Examples > Documentation.

Configure Spring Inversion of Control

In Spring, references to other beans (injected properties) are configured via the Spring configuration file applicationContext-web.xml.

Spring 2.5 annotation-driven configuration is used in MedRec-Spring. The application context is configured to have Spring automatically scan the Spring beans detecting Spring-specific annotations like @Service, so it is not necessary to declare every Spring bean in the XML configuration files. The configuration, in WL_HOME\samples\server\medrec-spring\modules\medrec\web\war\WEB-INF\applicationContext.xml, is as follows:

<context:component-scan base-package="com.oracle.medrec"/>

The dependency injection is mainly configured via the @Autowired annotation. For example, the WL_HOME\samples\server\medrec-spring\modules\medrec\domain\src\com\oracle\medrec\service\impl\RecordServiceImpl.java includes the following:

@Service("recordService")
@Transactional
public class RecordServiceImpl implements RecordService {

    @Autowired
    private RecordRepository recordRepository;

    @Autowired
    private PatientRepository patientRepository;

    @Autowired
    private PhysicianRepository physicianRepository;

All of these provide similar development experience as that of EJB 3.0. For more information, see "Annotation Type Autowired" in the Spring documentation at http://www.springsource.org/documentation/.

Enable the Spring Web Services Client Service

MedRec-Spring uses the Spring JaxWsPortProxyFactoryBean to expose a dynamic proxy for Web Services, as shown in the following example from WL_HOME\samples\server\medrec-spring\modules\physician\web\war\WEB-INF\applicationContext.xml:

<bean id="patientService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
   <property name="serviceInterface" value="com.oracle.physician.service.PatientService"/>
   <property name="wsdlDocumentUrl" 
         value="http://localhost:7011/medrec/webservices/PatientFacadeService?WSDL"/>
   <property name="namespaceUri" value="http://www.oracle.com/medrec/"/>
   <property name="serviceName" value="PatientFacadeService"/>
   <property name="portName" value="PatientFacadePort"/>
</bean>

<bean id="physicianService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
   <property name="serviceInterface" value="com.oracle.physician.service.PhysicianService"/>
   <property name="wsdlDocumentUrl"
         value="http://localhost:7011/medrec/webservices/PhysicianFacadeService?WSDL"/>
  <property name="namespaceUri" value="http://www.oracle.com/medrec/"/>
  <property name="serviceName" value="PhysicianFacadeService"/>
  <property name="portName" value="PhysicianFacadePort"/>
</bean>

<bean id="recordService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
  <property name="serviceInterface" value="com.oracle.physician.service.RecordService"/>
  <property name="wsdlDocumentUrl"
         value="http://localhost:7011/medrec/webservices/RecordFacadeService?WSDL"/>
  <property name="namespaceUri" value="http://www.oracle.com/medrec/"/>
  <property name="serviceName" value="RecordFacadeService"/>
  <property name="portName" value="RecordFacadePort"/>
</bean>

With this approach, you do not have to use the tool-generated Web Services stubs. For more information, see JaxWsPortProxyFactoryBean in the Spring documentation at http://www.springsource.org/documentation/.

Make JMS Services Available to the Application at Runtime

In Spring, you must configure JMS services so they are provided to the application during runtime. In MedRec-Spring, Oracle made JMS services available to the application at runtime by implementing the following code in the Spring configuration file WL_HOME\samples\server\medrec-spring\modules\medrec\web\war\WEB-INF\applicationContext.xml:

<!--- Messaging ************************************* -->
   <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
      <property name="connectionFactory" ref="connectionFactory"/>
   </bean>
   <jee:jndi-lookup id="connectionFactory" jndi-name="weblogic.jms.XAConnectionFactory"/>
        
   <jee:jndi-lookup id="patientNotificationQueue"
      jndi-name="com.oracle.medrec.jms.PatientNotificationQueue"/>
   <bean id="messageListener" 
   class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
      <property name="delegate" ref="patientNotifierBroker"/>
      <property name="defaultListenerMethod" value="notifyPatient"/>
   </bean>

   <bean id="messageListenerContainer"
         class="org.springframework.jms.listener.DefaultMessageListenerContainer">
      <!--<property name="taskExecutor" ref="taskExecutor"/>-->
      <property name="connectionFactory" ref="connectionFactory"/>
      <property name="messageListener" ref="messageListener"/>
      <property name="destination" ref="patientNotificationQueue"/>
      <!-- no need to use XA transaction now -->
      <property name="sessionTransacted" value="true"/>
</bean>

Here, various beans from the Spring framework are declared. In particular, the jmsTemplate wraps the underlying JMS APIs and is used to send messages. messageListenerContainer provides similar functionality as the Message-Driven Bean container, and the JMS listener in MedRec-Spring is registered to it.

Use JPA Data Access

MedRec-Spring use the standard Java Persistence API (JPA) to manage data sources. The configuration is in WL_HOME\samples\server\medrec-spring\modules\medrec\domain\src\META-INF\persistence.xml:

    <persistence-unit name="MedRec" transaction-type="JTA">
        <jta-data-source>jdbc/MedRecGlobalDataSourceXA</jta-data-source>
        <class>com.oracle.medrec.model.Address</class>
        <class>com.oracle.medrec.model.Administrator</class>
        <class>com.oracle.medrec.model.BaseEntity</class>
        <class>com.oracle.medrec.model.PersonName</class>
        <class>com.oracle.medrec.model.Patient</class>
        <class>com.oracle.medrec.model.Physician</class>
        <class>com.oracle.medrec.model.Prescription</class>
        <class>com.oracle.medrec.model.Record</class>
        <class>com.oracle.medrec.model.RegularUser</class>
        <class>com.oracle.medrec.model.User</class>
        <class>com.oracle.medrec.model.VersionedEntity</class>
        <class>com.oracle.medrec.model.VitalSigns</class>
        <properties>
            <property name="kodo.jdbc.SynchronizeMappings"
                      value="buildSchema"/>
        </properties>
    </persistence-unit>

MedRec-Spring does not declare a Data Access Object (DAO) in the Spring configuration file, because MedRec-Spring uses the annotation-driven approach (in this case @Repository for all the DAOs), so all of them will be automatically managed by Spring. For example, see the following in RecordRepositoryImpl.java:

@Repository
public class RecordRepositoryImpl
         extends EntityRepositorySupport<Record, Long> implements RecordRepository {

      public List<Record> findRecordsByPatientId(Long patientId) {
         return findByProperty("Record.findRecordsByPatientId", patientId);
      }
}

Use the Spring Transaction Abstraction Layer for Transaction Management

MedRec-Spring uses Spring 2.5 configuration to use the WebLogic JTA transaction manager and to enable annotation-based declarative transaction management. See the configuration in WL_HOME\samples\server\medrec-spring\modules\medrec\web\war\WEB-INF\applicationContext.xml:

   <tx:jta-transaction-manager/>

   <tx:annotation-driven/>

All the transaction demarcation is implemented via Spring's @Transactional annotation. This is similar to what is done in EJB 3.0 applications. See WL_HOME \samples\server\medrec-spring\modules\medrec\domain\src\com\oracle\medrec\service\impl\RecordServiceImpl.java:

@Service("recordService")
@Transactional
public class RecordServiceImpl implements RecordService {

…
   public void createRecord(Record record, Long physicianId, Long patientId) {

   }

   @Transactional(readOnly = true)
   public List<Record> getRecordsByPatientId(Long patientId) {
      }

   @Transactional(readOnly = true)
   public Record getRecord(Long id) {
   }
}