Skip Headers
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3)
B25386-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

3.2 Implementing Services with EJB Session Beans

A session bean exposes the functionality of the business layer to the client.


Note:

While you can expose methods on a TopLink entity directly as a business service, this is not the best practice for a Web application. This model will work for basic CRUD functionality, but even simple operations that include interactions between business layer objects require custom code that becomes difficult and unwieldy.

The most common use of a session bean is to implement the session facade J2EE design pattern. A session facade is a session bean that aggregates data and presents it to the application through the model layer. Session facades have methods that access entities as well as methods that expose services to clients. Session beans have a transactional context via the container, so they automatically support basic CRUD functionality.

Figure 3-1 Session Facade Functionality

This diagram shows Session Facade functionality

3.2.1 How to Create a Session Bean

To create a session bean, use the Create Session Bean wizard. This wizard is available from the New Gallery, in the Business Tier category.

The Create Session Bean wizard offers several options, such as EJB version, stateful and stateless sessions, remote and/or local interfaces, container- or bean-managed transactions (CMT or BMT), and choosing how to implement session facade methods. When you create a session bean for a TopLink project, you must choose an EJB 3.0 version session bean and a stateless session. You should also choose container-managed transactions (CMT), as bean-managed transactions (BMT) are beyond the scope of this book. The other options in the Create Session Bean wizard are discussed below.

3.2.1.1 Remote and Local Interfaces

The type of interface required depends on the client. If the client is running in the same virtual machine (VM), a local interface is usually the best choice. If the client runs on a separate VM, a remote interface is required. Most Web applications (JSF/JSP/Servlet) have the client and service running in the same VM, so a local interface is the best practice. Java clients (ADF Swing) run in a separate VM and require a remote interface.

3.2.1.2 Generating Session Facade Methods

A session facade contains core CRUD methods for transactions as well as methods to access entities. To generate session facade methods, select the checkbox for Generate Session Facade Methods in the Create Session Bean wizard, and use the following page to specify which methods to generate. JDeveloper automatically detects all the entities in the project and allows you to choose which entities and methods you want to create session facade methods for.

You can generate session facade methods for every entity in the same project, which can be useful for testing purposes, but is often too much clutter in a single session bean. Session beans are often tailored to a specific task, and contain no more information than is required for that task. Use the tree control to explicitly choose which methods to generate.

Figure 3-2 Selecting Session Facade Methods

This image shows the Session Facade Methods dialog

3.2.2 What Happens When You Create a Session Bean

The session bean class contains session-wide fields and service methods. When you create a session bean, JDeveloper generates the bean class and a separate file for the local and/or remote interfaces. The remote interface is the name of the session bean, for example, SRAdminFacade.java, while the bean class is appended with Bean.java and the local interface is appended with Local.java. You should not need to modify the interface files directly, so they are not visible in the Application Navigator. To view the interface files, use the System Navigator or the Structure Pane.

Example 3-1 SRAdminFacade.java Interface

package oracle.srdemo.model;
import java.util.List;
import javax.ejb.Local;
import oracle.srdemo.model.entities.ExpertiseArea;
import oracle.srdemo.model.entities.Product;
import oracle.srdemo.model.entities.User;
import oracle.toplink.sessions.Session;
 
@Local
public interface SRAdminFacade {
  Object mergeEntity(Object entity);
  Object persistEntity(Object entity);
  Object refreshEntity(Object entity);

  void removeEntity(Object entity);
  
  List<ExpertiseArea> findExpertiseByUserId(Integer userIdParam);
 
  ExpertiseArea createExpertiseArea(Product product, User user, Integer prodId, 
                                    Integer userId, String expertiseLevel, 
                                    String notes);
 
  Product createProduct(Integer prodId, String name, String image, 
                        String description);
 
  List<User> findAllStaffWithOpenAssignments();
 
  User createUser(Integer userId, String userRole, String email, 
                  String firstName, String lastName, String streetAddress, 
                  String city, String stateProvince, String postalCode, 
                  String countryId);
                  
  void updateStaffSkills(Integer userId, List<Integer> prodIds);
}

Example 3-2 SRAdminFacadeBean.java Bean Class

package oracle.srdemo.model;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.ejb.Stateless;
import oracle.srdemo.model.entities.ExpertiseArea;
import oracle.srdemo.model.entities.Product;
import oracle.srdemo.model.entities.User;
import oracle.toplink.sessions.Session;
import oracle.toplink.sessions.UnitOfWork;
import oracle.toplink.util.SessionFactory;
 
@Stateless(name="SRAdminFacade")
public class SRAdminFacadeBean implements SRAdminFacade {
  private SessionFactory sessionFactory;
 
  public SRAdminFacadeBean() {
    this.sessionFactory = 
        new SessionFactory("META-INF/sessions.xml", "SRDemo");
  }
  
  /**
   * Constructor used during testing to use a local connection
   * @param sessionName
   */
  public SRAdminFacadeBean(String sessionName) {
    this.sessionFactory = 
        new SessionFactory("META-INF/sessions.xml", sessionName);
 
  }  
 
  public Object mergeEntity(Object entity) {
    UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
    Object workingCopy = uow.readObject(entity);
    if (workingCopy == null)
      throw new RuntimeException("Could not find entity to update");
    uow.deepMergeClone(entity);
    uow.commit();
 
    return workingCopy;
  }
 
  public Object persistEntity(Object entity) {
    UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
    Object newInstance = uow.registerNewObject(entity);
    uow.commit();
 
    return newInstance;
  }
 
  public Object refreshEntity(Object entity) {
    Session session = getSessionFactory().acquireUnitOfWork();
    Object refreshedEntity = session.refreshObject(entity);
    session.release();
 
    return refreshedEntity;
  }
 
  public void removeEntity(Object entity) {
    UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
    Object workingCopy = uow.readObject(entity);
    if (workingCopy == null)
      throw new RuntimeException("Could not find entity to update");
    uow.deleteObject(workingCopy);
    uow.commit();
  }
 
  private SessionFactory getSessionFactory() {
    return this.sessionFactory;
  }
  
  public List<ExpertiseArea> findExpertiseByUserId(Integer userIdParam) {
    List<ExpertiseArea> result = null;
    
    if (userIdParam != null){
      Session session = getSessionFactory().acquireSession();
      Vector params = new Vector(1);
      params.add(userIdParam);
      result = (List<ExpertiseArea>)session.executeQuery("findExpertiseByUserId", ExpertiseArea.class, params);
      session.release();      
    }
 
    return result;
  }
 
  public ExpertiseArea createExpertiseArea(Product product, User user, 
                                           Integer prodId, Integer userId, 
                                           String expertiseLevel, 
                                           String notes) {
    UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
    ExpertiseArea newInstance = (ExpertiseArea)uow.newInstance(ExpertiseArea.class);
    
    if (product == null) {
        product = (Product)uow.executeQuery("findProductById", Product.class, prodId);
    }
    
    if (user == null){
        user = (User)uow.executeQuery("findUserById", User.class, userId); 
    }
    
    newInstance.setProduct(product);
    newInstance.setUser(user);
    newInstance.setProdId(prodId);
    newInstance.setUserId(userId);
    newInstance.setExpertiseLevel(expertiseLevel);
    newInstance.setNotes(notes);
    uow.commit();
 
    return newInstance;
  }
 
  public Product createProduct(Integer prodId, String name, String image, 
                               String description) {
    UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
    Product newInstance = (Product)uow.newInstance(Product.class);
    newInstance.setProdId(prodId);
    newInstance.setName(name);
    newInstance.setImage(image);
    newInstance.setDescription(description);
    uow.commit();
 
    return newInstance;
  }
 
  public List<User> findAllStaffWithOpenAssignments() {
    Session session = getSessionFactory().acquireSession();
    List<User> result = 
      (List<User>)session.executeQuery("findAllStaffWithOpenAssignments", User.class);
      session.release();
    return result;
  }
 
  public User createUser(Integer userId, String userRole, String email, 
                         String firstName, String lastName, 
                         String streetAddress, String city, 
                         String stateProvince, String postalCode, 
                         String countryId) {
    UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
    User newInstance = (User)uow.newInstance(User.class);
    newInstance.setUserId(userId);
    newInstance.setUserRole(userRole);
    newInstance.setEmail(email);
    newInstance.setFirstName(firstName);
    newInstance.setLastName(lastName);
    newInstance.setStreetAddress(streetAddress);
    newInstance.setCity(city);
    newInstance.setStateProvince(stateProvince);
    newInstance.setPostalCode(postalCode);
    newInstance.setCountryId(countryId);
    uow.commit();
 
    return newInstance;
  }
  
  public void updateStaffSkills(Integer userId, List<Integer> prodIds) {
    List<Integer> currentSkills;
    
    if (userId != null) {
        List<ExpertiseArea> currentExpertiseList =  findExpertiseByUserId(userId);
        currentSkills = new ArrayList(currentExpertiseList.size());
        
        //Look for deletions
        for(ExpertiseArea expertise:currentExpertiseList){
            Integer prodId = expertise.getProdId();
            currentSkills.add(prodId);
    
            if (!prodIds.contains(prodId)){
                removeEntity(expertise);
            }
        }
        
        //Look for additions
        for (Integer newSkillProdId: prodIds){
            if(!currentSkills.contains(newSkillProdId)){
                //need to add
                this.createExpertiseArea(null, null,newSkillProdId,userId,"Qualified",null);
            }
        }
    }
  }
}

3.2.3 What You May Need to Know When Creating a Session Bean

Typically you create one session facade for every logical unit in your application. A task could be defined in a large scope, by a role for instance, such as creating a session facade for administrative client operations and another session facade for customer client operations.How you create and name your session facades can facilitate UI development, so tailoring your session facades toward a particular task and using names that describe the task is a good practice.

When you generate session facade methods, a findAll() method is created by default for each entity. If you do not want to generate this method, deselect it in the tree control on the Session Facade Options page.

When creating or editing session facade methods, you cannot select both TopLink and EJB entities. If the project is enabled for TopLink entities, only those entities will be available as session facade methods. Support for combining TopLink and EJB entities in a single session facade is planned for a future release.

3.2.4 How to Update an Existing Session Bean With New Entities

New session beans can be created at any time using the wizard. However, you may have an existing session bean that already contains custom implementation code that you want to update with new persistent data objects or methods.

To update an existing session bean, right click on the session bean and choose Edit Session Facade. Use the Session Facade Options dialog to select the entities and methods to expose. Note that if you have created new entities, the Session Facade Options dialog will display new entities in the same project, but cannot detect entities in different projects.